<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>JavaScript 精讲 | Justic</title><meta name="keywords" content="JavaScript"><meta name="author" content="Justic"><meta name="copyright" content="Justic"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="一、JavaScript基础1、基本数据类型介绍所有的编程语言都有数据类型的概念。 在JavaScript中，数据类型可以分为基本数据类型和引用数据类型。其中基本数据类型包括Undefined,Null,Boolean,Number,String5种类型。在ES6中新增了一种基本的数据类型Symbol. 引用类型有Object,Function,Array,Date等。 问题：两种类型有什么区别？">
<meta property="og:type" content="article">
<meta property="og:title" content="JavaScript 精讲">
<meta property="og:url" content="http://example.com/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/index.html">
<meta property="og:site_name" content="Justic">
<meta property="og:description" content="一、JavaScript基础1、基本数据类型介绍所有的编程语言都有数据类型的概念。 在JavaScript中，数据类型可以分为基本数据类型和引用数据类型。其中基本数据类型包括Undefined,Null,Boolean,Number,String5种类型。在ES6中新增了一种基本的数据类型Symbol. 引用类型有Object,Function,Array,Date等。 问题：两种类型有什么区别？">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg">
<meta property="article:published_time" content="2022-07-13T12:05:37.000Z">
<meta property="article:modified_time" content="2022-07-14T13:00:08.798Z">
<meta property="article:author" content="Justic">
<meta property="article:tag" content="JavaScript">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="http://example.com/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'JavaScript 精讲',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-07-14 21:00:08'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><!-- hexo injector head_end start --><link rel="stylesheet" href="https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/clock.min.css" /><!-- hexo injector head_end end --><meta name="generator" content="Hexo 6.2.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "" data-lazy-src="https://portrait.gitee.com/uploads/avatars/user/2982/8948190_JIAXInT_1624177607.png!avatar200" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">25</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">2</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">3</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-graduation-cap"></i><span> 博文</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw fa fa-archive"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw fa fa-folder-open"></i><span> 归档</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/project/"><i class="fa-fw fas fa-images"></i><span> 项目</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/messageboard/"><i class="fa-fw fa fa-paper-plane"></i><span> 留言板</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于笔者</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">Justic</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fa fa-graduation-cap"></i><span> 博文</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw fa fa-archive"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw fa fa-folder-open"></i><span> 归档</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/project/"><i class="fa-fw fas fa-images"></i><span> 项目</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/messageboard/"><i class="fa-fw fa fa-paper-plane"></i><span> 留言板</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于笔者</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">JavaScript 精讲</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-13T12:05:37.000Z" title="发表于 2022-07-13 20:05:37">2022-07-13</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-14T13:00:08.798Z" title="更新于 2022-07-14 21:00:08">2022-07-14</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/JavaScript/">JavaScript</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">69.2k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>271分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="JavaScript 精讲"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span><span class="post-meta-separator">|</span><span class="post-meta-commentcount"><i class="far fa-comments fa-fw post-meta-icon"></i><span class="post-meta-label">评论数:</span><a href="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/" itemprop="commentCount"><i class="fa-solid fa-spinner fa-spin"></i></span></a></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="一、JavaScript基础"><a href="#一、JavaScript基础" class="headerlink" title="一、JavaScript基础"></a>一、JavaScript基础</h1><h2 id="1、基本数据类型介绍"><a href="#1、基本数据类型介绍" class="headerlink" title="1、基本数据类型介绍"></a>1、基本数据类型介绍</h2><p>所有的编程语言都有数据类型的概念。</p>
<p>在<code>JavaScript</code>中，数据类型可以分为基本数据类型和引用数据类型。其中基本数据类型包括<code>Undefined</code>,<code>Null</code>,<code>Boolean</code>,<code>Number</code>,<code>String</code>5种类型。在<code>ES6</code>中新增了一种基本的数据类型<code>Symbol</code>.</p>
<p>引用类型有<code>Object</code>,<code>Function</code>,<code>Array</code>,<code>Date</code>等。</p>
<p>问题：两种类型有什么区别？</p>
<p>存储位置不同</p>
<table>
<thead>
<tr>
<th><strong>区别</strong></th>
<th>基本数据类型</th>
<th>引用数据类型</th>
</tr>
</thead>
<tbody><tr>
<td>存储位置</td>
<td>栈(stack)</td>
<td>堆(heap)</td>
</tr>
<tr>
<td>占据空间</td>
<td>小，大小固定</td>
<td>大，大小不固定</td>
</tr>
</tbody></table>
<p>引用数据类型在栈中存储了指针，该指针指向堆中该实体的起始地址。当解释器寻找引用值时，会首先检索其在栈中的地址，取得地址后从堆中获得实体。</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E4%B8%8E%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B.png"></p>
<p>下面我们先来回顾基本数据类型的内容，后面再复习引用类型的内容，以及看一下对应的常见的面试题。</p>
<h3 id="1-1-Undefined类型"><a href="#1-1-Undefined类型" class="headerlink" title="1.1 Undefined类型"></a>1.1 Undefined类型</h3><p><code>Undefined</code>类型只有一个唯一的字面值<code>undefined</code>,表示的含义是一个变量不存在。</p>
<p>问题：哪些场景中会出现<code>undefined</code>?</p>
<p>第一：使用只声明而未初始化的变量时，会返回<code>undefined</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a) <span class="comment">//undefined</span></span><br></pre></td></tr></table></figure>

<p>第二：获取一个对象的某个不存在的属性时，会返回<code>undefined</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=&#123;</span><br><span class="line">    <span class="attr">userName</span>:<span class="string">&#x27;zhangsan&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">age</span>)<span class="comment">//undefined</span></span><br></pre></td></tr></table></figure>

<p>第三：函数没有明确的返回值，却对函数的调用结果进行打印</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>()) <span class="comment">//undefined</span></span><br></pre></td></tr></table></figure>

<p>第四：函数定义的时候，使用了多个形参，但是在调用的时候传递的参数的数量少于形参数量，那么没有匹配上的参数就为<code>undefined</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">p1,p2,p3</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(p3) <span class="comment">//undefined</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">fn</span>(<span class="number">1</span>,<span class="number">2</span>)</span><br></pre></td></tr></table></figure>

<h3 id="1-2-Null类型"><a href="#1-2-Null类型" class="headerlink" title="1.2 Null类型"></a>1.2 Null类型</h3><p>​	<code>Null</code>类型只有一个唯一的字面值<code>null</code>,表示一个空指针的对象，这也是在使用<code>typeof</code>运行符检测<code>null</code>值时会返回<code>object</code>的原因。</p>
<p>问题：哪些场景中会出现<code>null</code>？</p>
<p>第一：一般情况下，如果声明的变量是为了以后保存某个值，则应该在声明时就将其赋值为<code>null</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=<span class="literal">null</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">userName</span>:<span class="string">&#x27;zhangsan&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">obj=<span class="title function_">foo</span>();</span><br></pre></td></tr></table></figure>

<p>第二：<code>JavaScript</code>在获取<code>DOM</code>元素时，如果没有获取到指定的元素对象，就会返回<code>null</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;#id&#x27;</span>) <span class="comment">//null</span></span><br></pre></td></tr></table></figure>

<p>第三：在使用正则表达式进行匹配的时候，如果没有匹配的结果，就会返回<code>null</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">&#x27;test&#x27;</span>.<span class="title function_">match</span>(<span class="regexp">/a/</span>);<span class="comment">// null</span></span><br></pre></td></tr></table></figure>

<h3 id="1-3-Undefined与null比较"><a href="#1-3-Undefined与null比较" class="headerlink" title="1.3 Undefined与null比较"></a>1.3 Undefined与null比较</h3><p><code>Undefined</code>和<code>Null</code>虽然是两种不同的基本数据类型，但是在某些情况也存在相同之处，下面看一下它们两者相同点和不同点。</p>
<p><strong>（1）相同点</strong></p>
<p> 第一：<code>Undefined</code>和<code>Null</code>两种数据类型都只有一个字面值，分别是<code>undefined</code>和<code>null</code>.</p>
<p>第二：<code>Undefined</code>和<code>Null</code>类型在转换为<code>Boolean</code>类型的值时，都会转换为<code>false</code>.</p>
<p>第三：在需要将两者转换成对象的时候，都会抛出一个<code>TypeError</code>的异常。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a;</span><br><span class="line"><span class="keyword">var</span> b=<span class="literal">null</span>;</span><br><span class="line">cosnole.<span class="title function_">log</span>(a.<span class="property">name</span>);<span class="comment">//Cannot read property &#x27;name&#x27; of undefined</span></span><br><span class="line">cosnole.<span class="title function_">log</span>(b.<span class="property">name</span>);<span class="comment">//Cannot read property &#x27;name&#x27; of undefined</span></span><br></pre></td></tr></table></figure>

<p>第四：<code>Undefined</code>类型派生自<code>Null</code>类型，所以在非严格相等的比较下，两者是相等的。如下面代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="literal">null</span>==<span class="literal">undefined</span> <span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p><strong>(2)不同点</strong></p>
<p>第一：<code>null</code>是<code>JavaScript</code>的关键字，而<code>undefined</code>是<code>JavaScript</code>的一个全局变量，也就是挂载在<code>window</code>对象上的一个变量，并不是关键字。</p>
<p>第二：在使用<code>typeof</code>运算符进行检测时，<code>Undefined</code>类型的值会返回<code>undefined</code>.而<code>Null</code>类型的值返回为<code>object</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="literal">undefined</span> ;<span class="comment">//undefined</span></span><br><span class="line"><span class="keyword">typeof</span> <span class="literal">null</span> ;<span class="comment">//object</span></span><br></pre></td></tr></table></figure>

<p>第三：在需要进行字符串类型的转换时，<code>null</code>会转换成字符串<code>null</code>,而<code>undefined</code>会转换字符串<code>undefined</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="literal">undefined</span>+<span class="string">&quot; abc&quot;</span> <span class="comment">//&quot;undefined abc&quot;</span></span><br><span class="line"><span class="literal">null</span>+<span class="string">&quot; abc&quot;</span> <span class="comment">//&quot;null abc&quot;</span></span><br></pre></td></tr></table></figure>

<p>第四：在进行数值类型的转换时，<code>undefined</code>会转换为<code>NaN</code>,无法参与计算，而<code>null</code>会转换为<code>0</code>,可以参与计算。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="literal">undefined</span> +<span class="number">0</span>;<span class="comment">// NaN</span></span><br><span class="line"><span class="literal">null</span>+<span class="number">0</span> ;<span class="comment">// 0</span></span><br></pre></td></tr></table></figure>

<p>第五：建议：无论在什么情况下都没有必要将一个变量显示的赋值为<code>undefined</code>。如果需要定义某个变量来保存将来要使用的对象，应该将其初始化为<code>null</code>.</p>
<h3 id="1-4-Boolean类型"><a href="#1-4-Boolean类型" class="headerlink" title="1.4  Boolean类型"></a>1.4  Boolean类型</h3><p><code>Boolean</code>类型(布尔类型)的字面量只有两个，分别是<code>true</code>和<code>false</code>,它们是区分大小写的。</p>
<p><code>Boolean</code>类型使用最多的场景就是用于<code>if</code>语句的判断。在<code>JavaScript</code>中，<code>if</code>语句可以接受任何类型的表达式，即<code>if(a)</code>语句中的<code>a</code>,可以是<code>Boolean</code>,<code>Number</code>,<code>String</code>,<code>Object</code>，<code>Null</code>,<code>Undefined</code>等类型。</p>
<p>如果<code>a</code>不是<code>Boolean</code>类型的值，那么<code>JavaScript</code>解析器会自动调用<code>Boolean( )</code>函数对<code>a</code>进行类型的转换，返回最终符合<code>if</code>语句判断的<code>true</code>或者是<code>false</code>值。</p>
<p>不同类型与<code>Boolean</code>类型的值的转换是<code>Boolean</code>类型的重点。</p>
<p>第一：<code>String</code>类型转换为<code>Boolean</code>类型</p>
<p>空字符都会转换成<code>false</code>,而任何非空字符串都会转换为<code>true</code></p>
<p>第二：<code>Number</code>类型转换为<code>Boolean</code>类型</p>
<p><code>0</code>和<code>NaN</code>都会转换为<code>false</code>.而除了<code>0</code>和<code>NaN</code>以外都会转换<code>true</code>.</p>
<p>第三：<code>Object</code>类型转换<code>Boolean</code>类型</p>
<p>如果<code>object</code>为<code>null</code>时，会转换为<code>false</code>,如果<code>object</code>不为<code>null</code>，则都会转换成<code>true</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=&#123;&#125;</span><br><span class="line"><span class="title class_">Boolean</span>(obj) <span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> obj=<span class="literal">null</span></span><br><span class="line"><span class="title class_">Boolean</span>(obj)<span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>第四：<code>Function</code>类型转换<code>Boolean</code>类型</p>
<p>任何<code>Function</code>类型都会转换为<code>true</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> fn=<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Boolean</span>(fn)<span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>第五：<code>Null</code>类型转换为<code>Boolean</code>类型，我们知道<code>Null</code>类型只有一个<code>null</code>值，会转换为<code>false</code>.</p>
<p>第六：<code>Undefined</code>类型转换<code>Boolean</code>类型，我们知道<code>Undefined</code>类型只有一个<code>undefined</code>值，会转换为<code>false</code>.</p>
<h3 id="1-5-Number类型"><a href="#1-5-Number类型" class="headerlink" title="1.5 Number类型"></a>1.5 Number类型</h3><p>在<code>JavaScript</code>中，<code>Number</code>类型的数据包括了整型数据，也包括了浮点型数据。</p>
<p>我们先来看一下整型的处理。整型可以是十进制，也可以通过八进制或者是十六进制来表示。</p>
<p>第一：八进制：如果想要用八进制来表示一个数值，那么首位必须是0，其它位必须是0–7的数字，如果后面的数字大于7，则破坏了八进制的规则，这时会被当作十进制数来处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num1=<span class="number">024</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1) <span class="comment">//20</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num2=<span class="number">079</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num2) <span class="comment">//79</span></span><br></pre></td></tr></table></figure>

<p><code>num1</code>第一位是<code>0</code>表示八进制，后面每位数字都是在<code>0--7</code>之间的，所以符合八进制规则，最终转换为十进制为<code>20</code></p>
<p><code>num2</code>的第一位也是0，但是最后一位已经超过了7，所以不属于八进制，这里直接作为十进制来处理，最终输出的结果为79.</p>
<p>第二：十六进制：</p>
<p>如果想用十六进制表示一个数值，那么前面两位必须是<code>0x</code>,其它的位必须是(0–9,<code>a--f</code>或者<code>A--F</code>).如果超出了这个范围，则会抛出异常。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num1=<span class="number">0x5f</span> <span class="comment">//95</span></span><br><span class="line"><span class="keyword">var</span> num2=<span class="title class_">Ox5</span>h <span class="comment">//Uncaught SyntaxError: Invalid or unexpected token</span></span><br></pre></td></tr></table></figure>

<p>与<code>Boolean</code>类型一样，当其它类型在与<code>Number</code>类型进行数据转换时，也会遵守一定的规则。</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="1-5-1-Number类型转换"><a href="#1-5-1-Number类型转换" class="headerlink" title="1.5.1 Number类型转换"></a>1.5.1 Number类型转换</h4><p>在实际开发中，我们经常会遇到将其他类型的值转换为<code>Number</code>类型的情况。在<code>JavaScript</code>中，一共有3个函数可以完成这种转换，分别是<code>Number()</code>函数，<code>parseInt( )</code>函数,<code>parseFloat( )</code>函数。下面我们看一下这些函数需要注意的事项。</p>
<p><strong>Number( )函数</strong></p>
<p><code>Number( )</code>函数可以用于将任何类型转换为<code>Number</code>类型，它在转换时遵循如下规则：</p>
<p>第一：如果是数字，会按照对应的进制数据格式，统一转换为十进制返回。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="number">10</span>) <span class="comment">//10</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="number">010</span>) <span class="comment">// 8, 010是八进制的数据，转换成十进制是8</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="number">0x10</span>) <span class="comment">// 16,0x10是十六进制的数据，转换成十进制是16</span></span><br></pre></td></tr></table></figure>

<p>第二：如果是<code>Boolean</code>类型的值，<code>true</code>返回1,<code>false</code>返回是的0</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="literal">true</span>) <span class="comment">//1</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="literal">false</span>) <span class="comment">//0</span></span><br></pre></td></tr></table></figure>

<p>第三：如果值为<code>null</code>,则返回0</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="literal">null</span>) <span class="comment">//0</span></span><br></pre></td></tr></table></figure>

<p>第四：如果值为<code>undefined</code>,则返回<code>NaN</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="literal">undefined</span>) <span class="comment">//NaN</span></span><br></pre></td></tr></table></figure>

<p>第五：如果值为字符串类型，需要遵循如下规则</p>
<p>  （1）如果该字符串只包含了数字，则会直接转换成十进制数；如果数字前面有0，则会直接忽略掉这个0。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;21&#x27;</span>) <span class="comment">//21</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;012&#x27;</span>) <span class="comment">//12</span></span><br></pre></td></tr></table></figure>

<p>(2) 如果字符串是有效的浮点数形式，则会直接转成对应的浮点数，前置的多个重复的0会被删除，只保留一个。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;0.12&#x27;</span>) <span class="comment">//0.12</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;00.12&#x27;</span>) <span class="comment">//0.12</span></span><br></pre></td></tr></table></figure>

<p>(3)如果字符串是有效的十六进制形式，则会转换为对应的十进制数值</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;0x12&#x27;</span>) <span class="comment">//18</span></span><br></pre></td></tr></table></figure>

<p>(4) 如果字符串是有效的八进制，则不会按照八进制转换，而是直接按照十进制转换并输出，因为前置的0会被直接忽略掉。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;010&#x27;</span>) <span class="comment">//10</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;0020&#x27;</span>) <span class="comment">//20</span></span><br></pre></td></tr></table></figure>

<p>(5)如果字符串为空，即字符串不包含任何字符，或为连续多个空格，则会转换为0.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;&#x27;</span>) <span class="comment">//0</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;     &#x27;</span>)<span class="comment">//0</span></span><br></pre></td></tr></table></figure>

<p>(6)如果字符串中包含了任何不适以上5种情况的其它格式内容，则会返回<code>NaN</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;123a&#x27;</span>) <span class="comment">//NaN</span></span><br><span class="line"><span class="title class_">Number</span>(<span class="string">&#x27;abc&#x27;</span>) <span class="comment">//NaN</span></span><br></pre></td></tr></table></figure>

<p>第六：如果是对象类型，则会调用对象的<code>valueOf( )</code>函数获取返回值，并且判断返回值能否转换为<code>Number</code>类型，如果不能，会调用对象的<code>toString( )</code>函数获取返回值，并且判断是否能够转换为<code>Number</code>类型。如果也不满足，则返回<code>NaN</code>.</p>
<p>以下是通过<code>valueOf( )</code>函数将对象转换成<code>Number</code>类型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=&#123;</span><br><span class="line">    <span class="attr">age</span>:<span class="string">&#x27;12&#x27;</span>,</span><br><span class="line">    <span class="attr">valueOf</span>:<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">age</span></span><br><span class="line">    &#125;,</span><br><span class="line">   </span><br><span class="line">  &#125;</span><br><span class="line"><span class="title class_">Number</span>(obj) <span class="comment">//12</span></span><br></pre></td></tr></table></figure>

<p>以下是通过<code>toString( )</code>函数将对象转换成<code>Number</code>类型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=&#123;</span><br><span class="line">    <span class="attr">age</span>:<span class="string">&#x27;21&#x27;</span>,</span><br><span class="line">    <span class="attr">toString</span>:<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">age</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Number</span>(obj)</span><br></pre></td></tr></table></figure>

<p><strong>parseInt( )函数</strong></p>
<p><code>parseInt()</code>函数用于解析一个字符串，并返回指定的基数对应的整数值。</p>
<p>语法格式： </p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(string,radix)</span><br></pre></td></tr></table></figure>

<p>其中<code>string</code>参数表示要被解析的值，如果该参数不是一个字符串，那么会使用<code>toString( )</code>函数将其转换成字符串。并且字符串前面的空白符会被忽略。</p>
<p><code>radix</code>表示的是进制转换的基数，可以是二进制，十进制，八进制和十六进制。默认值为10.</p>
<p>因为对相同的数采用不同进制进行处理时可能会得到不同的结果，所以在任何情况下使用<code>parseInt</code>函数时，建议都手动补充第二个参数。</p>
<p><code>parseInt( )</code>函数会返回字符串解析后的整数值，如果该字符串无法转换成<code>Number</code>类型，则会返回<code>NaN</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;aaa&#x27;</span>)<span class="comment">//NaN</span></span><br></pre></td></tr></table></figure>

<p>在使用<code>parseInt</code>函数将字符串转换成整数时，需要注意的问题：</p>
<p>第一：如果遇到传入的参数是非字符串类型的情况，则需要将其优先转换成字符串类型。即使传入的是整型数据。</p>
<p>第二：<code>parseInt( )</code>函数在做转换时，对于传入的字符串会采用前置匹配的原则。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">&quot;fg123&quot;</span>,<span class="number">16</span>)</span><br></pre></td></tr></table></figure>

<p>对于字符串<code>fg123</code>,首先从第一个字符开始，<code>f</code>是满足十六进制的数据的，因为十六进制数据的范围是<code>0--9</code>,<code>a--f</code>,所以保留<code>f</code>，然后是第二个字符<code>g</code>，它不满足十六进制数据范围，因此从第二个字符都最后一个字符全部舍弃，最终字符串只保留了字符<code>f</code>，然后将字符<code>f</code>转换成十六进制的数据，为15，因此最终返回的结果为<code>15</code>.</p>
<p>还要注意的一点就是，如果传入的字符串中涉及到了算术运算，则不会执行，算术符号会被当作字符处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;16*2&#x27;</span>)<span class="comment">// 16,这里直接当作字符串处理，并不会进行乘法的运算</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="number">16</span>*<span class="number">2</span>) <span class="comment">// 32 </span></span><br></pre></td></tr></table></figure>

<p>第三：对浮点数的处理</p>
<p>如果传入的值是浮点数，则会忽略小数点以及后面的数，直接取整。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="number">12.98</span>) <span class="comment">//12</span></span><br></pre></td></tr></table></figure>

<p>第四：<code>map( )</code>函数与<code>parseInt( )</code>函数的问题</p>
<p>我们这里假设有一个场景，存在一个数组，数组中的每个元素都是数字字符串，[‘1’,’2’,’3’,’4’]，如果将这个数组中的元素全部转换成整数，应该怎样处理呢？</p>
<p>这里我们可能会想到使用<code>map( )</code>函数，然后在该函数中调用<code>parseInt( )</code>函数来完成转换。所以代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">var</span> arr = [<span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span>, <span class="string">&quot;4&quot;</span>];</span><br><span class="line">     <span class="keyword">var</span> result = arr.<span class="title function_">map</span>(<span class="built_in">parseInt</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>执行上面程序得到的结果是：<code>[1,NaN,NaN,NaN]</code></p>
<p>为什么会出现这样的问题呢？</p>
<p>上面的代码等效如下的代码</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span>, <span class="string">&quot;4&quot;</span>];</span><br><span class="line">     <span class="comment">//   var result = arr.map(parseInt);</span></span><br><span class="line">     <span class="keyword">var</span> result = arr.<span class="title function_">map</span>(<span class="keyword">function</span> (<span class="params">val, index</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="built_in">parseInt</span>(val, index);</span><br><span class="line">     &#125;);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，可以发现，<code>parseInt</code>函数第二个参数实际上就是数组的索引值。所以，整体的形式如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;1&#x27;</span>,<span class="number">0</span>) <span class="comment">// 任何整数以0为基数取整时，都会返回本身，所以这里返回的是1</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;2&#x27;</span>,<span class="number">1</span>) <span class="comment">//注意parseInt第二个参数的取值范围为2--36，所以不满足条件，这里只能返回NaN</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;3&#x27;</span>,<span class="number">2</span>) <span class="comment">// 表示将3作为二进制来进行处理，但是二进制只有0和1，所以3超出了范围，无法转换，返回`NaN`</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">&#x27;4&#x27;</span>,<span class="number">3</span>) <span class="comment">//将4作为三进制来处理，但是4无法用三进制的数据表示，返回NaN</span></span><br></pre></td></tr></table></figure>

<p>所以当我们在<code>map( )</code>函数中使用<code>parseInt( )</code>函数时，不能直接将<code>parseInt( )</code>函数作为<code>map( )</code>函数的参数，而是需要在<code>map( )</code>函数的回调函数中使用,并尽量指定基数。代码如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span>, <span class="string">&quot;4&quot;</span>];</span><br><span class="line"><span class="keyword">var</span> result = arr.<span class="title function_">map</span>(<span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">parseInt</span>(val, <span class="number">10</span>);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>parseFloat( )函数</strong></p>
<p><code>parseFloat</code>函数用于解析一个字符串，返回对应的浮点数，如果给定值不能转换为数值，则返回<code>NaN</code></p>
<p>与<code>parseInt( )</code>函数相比，<code>parseFloat( )</code>函数没有进制的概念。</p>
<p>注意:</p>
<p>第一：如果字符串前面有空白符，则会直接忽略掉，如果第一个字符就无法解析，则会直接返回<code>NaN</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseFloat</span>(<span class="string">&#x27;  2.6&#x27;</span>)<span class="comment">// 2.6</span></span><br><span class="line"><span class="built_in">parseFloat</span>(<span class="string">&#x27;f2.6&#x27;</span>) <span class="comment">//NaN</span></span><br></pre></td></tr></table></figure>

<p>第二：对于小数点，只能正确匹配第一个，第二个小数点是无效的，它后面的字符也都将被忽略。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">parseFloat</span>(<span class="string">&#x27;12.23&#x27;</span>)<span class="comment">// 12.23</span></span><br><span class="line"><span class="built_in">parseFloat</span>(<span class="string">&#x27;12.23.39&#x27;</span>)<span class="comment">//12.23</span></span><br></pre></td></tr></table></figure>



<p><strong>总结:</strong></p>
<p>虽然<code>Number( )</code>,<code>parseInt( )</code>,<code>parseFloat( )</code>函数都能用于<code>Number</code>类型的转换，但是他们之间还是有一定的差异</p>
<p>第一：<code>Number( )</code> 函数转换的是传入的整个值，并不是像<code>parseInt( )</code>函数和<code>parseFloat( )</code>函数一样会从首位开始匹配符合条件的值。如果整个值不能被完整转换，则会返回<code>NaN</code></p>
<p>第二：<code>parseFloat( )</code>返回对应的浮点数，<code>parseInt( )</code>返回整数，并且<code>parseFloat( )</code>函数在解析时没有进制的概念，而<code>parseInt()</code></p>
<p>函数在解析时会依赖于出入的第二个参数来做值的转换。</p>
<h4 id="1-5-2-isNaN-函数与Number-isNaN-函数对比"><a href="#1-5-2-isNaN-函数与Number-isNaN-函数对比" class="headerlink" title="1.5.2  isNaN( )函数与Number.isNaN( )函数对比"></a>1.5.2  isNaN( )函数与Number.isNaN( )函数对比</h4><p><code>Number</code>类型数据中存在一个比较特殊的值<code>NaN</code>（<code>Not a Number</code>）,它表示应该返回数值却并未返回数值的情况。</p>
<p><code>NaN</code>存在的目的是在某些异常情况下保证程序的正常执行。例如<code>0/0</code>，在其他的语言中，程序会直接抛出异常，而在<code>JavaScript</code>中会返回<code>NaN</code>,程序可以正常运行。</p>
<p><code>NaN</code>有两个很明显的特点，第一个是任何涉及<code>NaN</code>的操作都会返回<code>NaN</code>,第二个是<code>NaN</code>与任何值都不相等，即使是与<code>NaN</code>本身相比。</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">NaN==NaN //false</span><br></pre></td></tr></table></figure>

<p>在判断<code>NaN</code>时，<code>ES5</code>提供了<code>isNaN</code>函数，<code>ES6</code>为<code>Number</code>类型增加了静态函数<code>isNaN( ).</code></p>
<p>问题：既然在<code>ES5</code>中提供了<code>isNaN</code>函数，为什么要在<code>ES6</code>中专门增加<code>Number.isNaN( )</code>函数呢？两者在使用上有什么区别？<br>我们先来看一下<code>isNaN( )</code>函数</p>
<p><code>isNaN( )</code>函数的作用是用来确定一个变量是不是<code>NaN</code>,<code>NaN</code>是一个<code>Number</code>类型的数值，只不过这个值无法用真实的数字表示。</p>
<p><code>isNaN</code>检测的机制：它在处理的时候会去判断传入的变量值能否转为数字，如果能转换成数字则会返回<code>false</code>,如果无法转换则会返回<code>true</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">isNaN</span>(<span class="title class_">NaN</span>)<span class="comment">//true</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="literal">undefined</span>) <span class="comment">//true</span></span><br><span class="line"><span class="built_in">isNaN</span>(&#123;&#125;)<span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="literal">true</span>)<span class="comment">// false ,Number(true)会转换成数字1</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="literal">false</span>)<span class="comment">// false,Number(false)会转换成数字0</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="literal">null</span>) <span class="comment">// false,Number(null)会转换成数字0</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="number">1</span>) <span class="comment">//false</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="string">&#x27;aaa&#x27;</span>) <span class="comment">//true 字符串aaa无法转换成数字</span></span><br><span class="line"><span class="built_in">isNaN</span>(<span class="string">&#x27;1&#x27;</span>) <span class="comment">//false 字符串“1”可以转换成数字1.</span></span><br></pre></td></tr></table></figure>

<p>**<code>Number.isNaN( )</code>**函数</p>
<p>既然在全局的环境中有了<code>isNaN( )</code>函数，为什么在<code>ES6</code>中会专门针对<code>Number</code>类型增加一个<code>isNaN</code>函数呢？</p>
<p>这是因为全局的<code>isNaN</code>函数本身存在误导性，而<code>ES6</code>中的<code>Number.isNaN( )</code>函数会在真正意义上去判断变量是否为<code>NaN</code>,不会做数据类型转换。只有在传入的值为<code>NaN</code>,才会返回<code>true</code>,传入其它类型的值时会返回<code>false</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Number</span>.<span class="built_in">isNaN</span>(<span class="title class_">NaN</span>)<span class="comment">// true</span></span><br><span class="line"><span class="title class_">Number</span>.<span class="built_in">isNaN</span>(<span class="number">1</span>) <span class="comment">//false</span></span><br><span class="line"><span class="title class_">Number</span>.<span class="built_in">isNaN</span>(<span class="literal">null</span>) <span class="comment">//false</span></span><br><span class="line"><span class="title class_">Number</span>.<span class="built_in">isNaN</span>(<span class="literal">undefined</span>) <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>如果在非<code>ES6</code>环境中想用<code>ES6</code>中的<code>isNaN( )</code>函数，怎样处理呢？</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span>(!<span class="title class_">Number</span>.<span class="property">isNaN</span>)&#123;</span><br><span class="line">    <span class="title class_">Number</span>.<span class="property">isNaN</span>=<span class="keyword">function</span>(<span class="params">n</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> n!==n</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在所有类型的数据中，如果一个变量和自身进行比较，只有在变量为<code>NaN</code>时才会返回<code>false</code>,其它情况都是返回的<code>true</code>.</p>
<p>所以<code>n!==n</code>返回<code>true</code>,也只有在<code>n</code>的值为<code>NaN</code>的时候才会成立。</p>
<p><strong>总结：</strong></p>
<p><code>isNaN( )</code>函数与<code>Number.isNaN( )</code>函数的区别如下：</p>
<p>第一：<code>isNaN( )</code>函数在判断是否为<code>NaN</code>时，需要进行数据类型转换，只有在无法转换为数字时才会返回<code>true</code></p>
<p>第二：<code>Number.isNaN( )</code>函数在判断是否为<code>NaN</code>时，只需要判断传入的值是否为<code>NaN</code>,并不会进行数据类型转换。</p>
<h3 id="1-6-String类型"><a href="#1-6-String类型" class="headerlink" title="1.6 String类型"></a>1.6 String类型</h3><p>在<code>JavaScript</code>中的<code>String</code>类型可以通过双引号表示，也可以通过单引号表示，并且这两种方式是完全等效的。</p>
<h4 id="1-6-1-String类型定义"><a href="#1-6-1-String类型定义" class="headerlink" title="1.6.1 String类型定义"></a>1.6.1 String类型定义</h4><p>在<code>JavaScript</code>中有3种方式来创建字符串，分别是字符串字面量，直接调用<code>String( )</code>函数，还有就是通过<code>new String( )</code>构造函数的方式。</p>
<p><strong>字面量</strong></p>
<p>字符串字面量就是直接通过单引号或者是双引号定义字符串的方式。</p>
<p>注意：单引号和双引号是等价的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> str=<span class="string">&#x27;hello&#x27;</span></span><br><span class="line"><span class="keyword">var</span> str2=<span class="string">&quot;JavaScript&quot;</span></span><br></pre></td></tr></table></figure>

<p><strong>直接调用<code>String( )</code>函数</strong></p>
<p>直接调用<code>String( )</code>函数，会将传入的任何类型的值转换成字符串类型。在转换的时候，需要遵循如下的规则：</p>
<p>第一：如果是<code>Number</code>类型的值，则直接转换成对应的字符串。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">String</span>(<span class="number">123</span>) <span class="comment">// &#x27;123&#x27;</span></span><br><span class="line"><span class="title class_">String</span>(<span class="number">123.56</span>) <span class="comment">// &quot;123.56&quot;</span></span><br></pre></td></tr></table></figure>

<p>第二：如果是<code>Boolean</code>类型的值，则直接转换成字符串的<code>&quot;true&quot;</code>或者是<code>&quot;false&quot;</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">String</span>(<span class="literal">true</span>)<span class="comment">// &quot;true&quot;</span></span><br><span class="line"><span class="title class_">String</span>(<span class="literal">false</span>) <span class="comment">// &quot;false&quot;</span></span><br></pre></td></tr></table></figure>

<p>第三：如果值为<code>null</code>,直接转换成字符串的<code>&quot;null&quot;</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">String</span>(<span class="literal">null</span>) <span class="comment">// &quot;null&quot;</span></span><br></pre></td></tr></table></figure>

<p>第四：如果值为<code>undefined</code>,则转换成字符串的<code>undefined</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">String</span>(<span class="literal">undefined</span>) <span class="comment">//&quot;undefined&quot;</span></span><br></pre></td></tr></table></figure>

<p><strong>new String( )构造函数</strong></p>
<p>这种方式是使用<code>new</code>运算符来创建一个<code>String</code>的实例。转换的规则和<code>String( )</code>函数是一样的，最后返回的是一个<code>String</code>类型的对象实例。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">String</span>(<span class="number">678</span>) <span class="comment">//返回的对象中有length属性，并且可以通过下标获取对应的值。</span></span><br></pre></td></tr></table></figure>

<p><strong>三种创建方式的区别</strong></p>
<p>使用字符串字面量方式和直接调用<code>String( )</code>函数的方式得到的字符串都是基本字符串，而通过<code>new String( )</code>方式生成的字符串是字符串对象。</p>
<p>基本字符串在比较的时候，只需要比较字符串的值即可，而在比较字符串对象时，比较的是对象所在的地址。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> str=<span class="string">&#x27;hello&#x27;</span></span><br><span class="line"><span class="keyword">var</span> str2=<span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>)</span><br><span class="line">str===str2 <span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> str3=<span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> str4=<span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>)</span><br><span class="line">str3===str4 <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>对于<code>str</code>与<code>str2</code>都是基本字符串，只是比较字符串的值就可以了，所以两者是相等的。</p>
<p>而对于<code>str3</code>与<code>str4</code>都是通过<code>String</code>类型的实例，所以在比较的时候需要判断变量是否指向了同一个对象，也就是内存地址是否相同，很明显，<code>str3</code>与<code>str4</code>都是在内存中新生成的地址，彼此各不相同。</p>
<p><strong>函数调用</strong></p>
<p>在<code>String</code>对象的原型链有一系列的函数，例如<code>indexOf( )</code>,<code>substring()</code>等等。</p>
<p>通过<code>String</code>对象的实例可以调用这些函数做字符串的处理。</p>
<p>但是，我们发现了一个问题，就是采用字面量方式定义的字符串也能够直接调用原型链上的这些函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">&#x27;hello&#x27;</span>.<span class="title function_">indexOf</span>(<span class="string">&#x27;o&#x27;</span>) <span class="comment">//4</span></span><br></pre></td></tr></table></figure>

<p>这是为什么呢？</p>
<p>实际上基本字符串本身是没有字符串对象上的这些函数的，而在基本字符串调用字符串对象才有的函数时，<code>JavaScript</code>会自动将基本字符串转换为字符串对象，形成一种包装的类型，这样基本字符串就可以正常调用字符串对象的方法了。</p>
<h4 id="1-6-2-字符串常见算法"><a href="#1-6-2-字符串常见算法" class="headerlink" title="1.6.2  字符串常见算法"></a>1.6.2  字符串常见算法</h4><p>我们来看一下常见的<code>String</code>类型中的算法，这些在面试的时候也是经常被问到的。</p>
<p><strong>第一：字符串逆序输出</strong></p>
<p>字符串逆序输出就是将一个字符串以相反的顺序进行输出。</p>
<p>例如<code>abcdef</code>输出的结果是<code>fedcba</code></p>
<p>第一种算法</p>
<p>这里我们是借助与数组的<code>reverse()</code>函数来实现。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">reverseString</span>(<span class="params">str</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> str.<span class="title function_">split</span>(<span class="string">&quot;&quot;</span>).<span class="title function_">reverse</span>().<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">reverseString</span>(<span class="string">&quot;abcdef&quot;</span>));</span><br></pre></td></tr></table></figure>



<p>第二种算法：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr=<span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="string">&#x27;abcdef&#x27;</span>) <span class="comment">//转换成数组,这里比第一种方式简单</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">reverse</span>().<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>))</span><br></pre></td></tr></table></figure>

<p>第三种算法：</p>
<p>这里可以通过字符串本身提供的<code>chartAt</code>函数来完成。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">reverseString2</span>(<span class="params">str</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> result = <span class="string">&quot;&quot;</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> i = str.<span class="property">length</span> - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line">        result += str.<span class="title function_">charAt</span>(i);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">reverseString2</span>(<span class="string">&quot;abcdef&quot;</span>));</span><br></pre></td></tr></table></figure>



<p><strong>统计字符串中出现次数最多的字符及出现的次数</strong></p>
<p>假如有一个字符串<code>javascriptjavaabc</code>,其中出现最多的字符是<code>a</code>,出现了5次。</p>
<p><strong>算法1</strong></p>
<p>思想：通过<code>key-value</code>形式的对象存储字符串以及字符串出现的次数，然后逐个判断出现次数最大的值，同时获取对应的字符。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">getMaxCount</span>(<span class="params">str</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> json = &#123;&#125;; <span class="comment">//表示key-value结构的对象</span></span><br><span class="line">        <span class="comment">//遍历str的每一个字符得到key-value形式的对象</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; str.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="comment">//判断json对象中是否有当前从str字符串中取出来的某个字符。</span></span><br><span class="line">          <span class="keyword">if</span> (!json[str.<span class="title function_">charAt</span>(i)]) &#123;</span><br><span class="line">            <span class="comment">//如果不存在，把当前字符作为key添加到json对象中，值为1</span></span><br><span class="line">            json[str.<span class="title function_">charAt</span>(i)] = <span class="number">1</span>;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//如果存在，则让value值加1</span></span><br><span class="line">            json[str.<span class="title function_">charAt</span>(i)]++;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//存储出现次数最多的字符</span></span><br><span class="line">        <span class="keyword">var</span> maxCountChar = <span class="string">&quot;&quot;</span>;</span><br><span class="line">        <span class="comment">//存储出现最多的次数</span></span><br><span class="line">        <span class="keyword">var</span> maxCount = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//遍历json对象，找出出现次数最大的值</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> json) &#123;</span><br><span class="line">          <span class="keyword">if</span> (json[key] &gt; maxCount) &#123;</span><br><span class="line">            maxCount = json[key];</span><br><span class="line">            maxCountChar = key;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">          <span class="string">&quot;出现最多的字符是&quot;</span> + maxCountChar + <span class="string">&quot;,共出现了&quot;</span> + maxCount + <span class="string">&quot;次&quot;</span></span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> str = <span class="string">&quot;javascriptjavaabc&quot;</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getMaxCount</span>(str));</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p><strong>算法2</strong></p>
<p>思路：这里主要是对字符串进行排序，然后通过<code>lastIndexOf()</code>函数获取索引值后，判断索引值的大小以获取出现的最大次数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">getMaxCount</span>(<span class="params">str</span>) &#123;</span><br><span class="line">       <span class="comment">//定义两个变量,分别表示出现最大次数和对应的字符。</span></span><br><span class="line">       <span class="keyword">var</span> maxCount = <span class="number">0</span>,</span><br><span class="line">         maxCountChar = <span class="string">&quot;&quot;</span>;</span><br><span class="line">       <span class="comment">//处理成数组，调用sort()函数排序，再处理成字符串</span></span><br><span class="line">       str = str.<span class="title function_">split</span>(<span class="string">&quot;&quot;</span>).<span class="title function_">sort</span>().<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, j = str.<span class="property">length</span>; i &lt; j; i++) &#123;</span><br><span class="line">         <span class="keyword">var</span> char = str[i];</span><br><span class="line">         <span class="comment">//计算每个字符出现的次数</span></span><br><span class="line">         <span class="keyword">var</span> charCount = str.<span class="title function_">lastIndexOf</span>(char) - i + <span class="number">1</span>;</span><br><span class="line">         <span class="comment">//与次数最大值进行比较</span></span><br><span class="line">         <span class="keyword">if</span> (charCount &gt; maxCount) &#123;</span><br><span class="line">           <span class="comment">//更新maxCount与maxCountChar的值</span></span><br><span class="line">           maxCount = charCount;</span><br><span class="line">           maxCountChar = char;</span><br><span class="line">         &#125;</span><br><span class="line">         <span class="comment">//变更索引为字符出现的最后位置</span></span><br><span class="line">         i = str.<span class="title function_">lastIndexOf</span>(char);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="string">&quot;出现最多的字符是&quot;</span> + maxCountChar + <span class="string">&quot;,出现次数为&quot;</span> + maxCount;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getMaxCount</span>(<span class="string">&quot;caa&quot;</span>));</span><br></pre></td></tr></table></figure>



<p><strong>去除字符串中重复的字符</strong></p>
<p>假如存在一个字符串<code>&quot;javascriptjavaabc&quot;</code>,其中存有重复的字符，现在需要将这些重复的字符去掉，只保留一个。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">removeStringChar</span>(<span class="params">str</span>) &#123;</span><br><span class="line">       <span class="comment">//结果数组</span></span><br><span class="line">       <span class="keyword">var</span> result = [];</span><br><span class="line">       <span class="comment">//key-value形式的对象</span></span><br><span class="line">       <span class="keyword">var</span> json = &#123;&#125;;</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; str.<span class="property">length</span>; i++) &#123;</span><br><span class="line">         <span class="comment">//当前处理的字符</span></span><br><span class="line">         <span class="keyword">var</span> char = str[i];</span><br><span class="line">         <span class="comment">//判断是否在对象中</span></span><br><span class="line">         <span class="keyword">if</span> (!json[char]) &#123;</span><br><span class="line">           <span class="comment">//将value值设置为true</span></span><br><span class="line">           json[char] = <span class="literal">true</span>;</span><br><span class="line">           <span class="comment">//添加到结果数组中</span></span><br><span class="line">           result.<span class="title function_">push</span>(char);</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> result.<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> str = <span class="string">&quot;javascriptjavaabc&quot;</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">removeStringChar</span>(str));</span><br></pre></td></tr></table></figure>



<p><strong>算法2</strong></p>
<p>这里可以使用<code>ES6</code>中的<code>Set</code>数据结构，可以结构具有自动去重的特性，可以直接将数组元素去重。</p>
<p>下面先来看一下<code>Set</code>的基本使用方式</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> set = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">4</span>,]);</span><br><span class="line"><span class="comment">//console.log(set)  // Set(4) &#123;1, 2, 3, 4&#125;</span></span><br><span class="line">[...set] <span class="comment">// [1, 2, 3, 4] 通过扩展运算符将set中的内容转换成数组，同时可以看到已经去重。</span></span><br></pre></td></tr></table></figure>

<p>基本思路：</p>
<p>（1）将字符串处理成数组，然后作为参数传递给<code>Set</code>的构造函数，通过<code>new</code>运算符生成一个<code>Set</code>实例。</p>
<p>(2)  将<code>Set</code>通过扩展运算符(…)转换成数组的形式，最终转换成字符串获得需要的结果。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">removeStringChar</span>(<span class="params">str</span>) &#123;</span><br><span class="line">       <span class="keyword">let</span> set = <span class="keyword">new</span> <span class="title class_">Set</span>(str.<span class="title function_">split</span>(<span class="string">&quot;&quot;</span>));</span><br><span class="line">       <span class="keyword">return</span> [...set].<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> str = <span class="string">&quot;javascriptjavaabc&quot;</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">removeStringChar</span>(str));</span><br></pre></td></tr></table></figure>



<p><strong>判断一个字符串是否为回文字符串</strong></p>
<p>回文字符串指的是一个字符串正序和倒序是相同的，例如字符串<code>abcdcba</code>是一个回文字符串，而字符串<code>abcedba</code>就不是一个回文字符串。</p>
<p>需要注意的是，这里不区分字符的大小写，即<code>a</code>和<code>A</code>在判断的时候是相等的。</p>
<p><strong>算法1</strong></p>
<p>主要思想是将字符串按从前往后顺序的字符与按从后往前顺序的字符逐个进行比较，如果遇到不一样的值则直接返回<code>false</code>,否则返回<code>true</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">isEequStr</span>(<span class="params">str</span>) &#123;</span><br><span class="line">       <span class="comment">//空字符串则直接返回true</span></span><br><span class="line">       <span class="keyword">if</span> (!str.<span class="property">length</span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//统一转换成小写，同时再将其转换成数组</span></span><br><span class="line">       str = str.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">       <span class="keyword">var</span> start = <span class="number">0</span>,</span><br><span class="line">         end = str.<span class="property">length</span> - <span class="number">1</span>;</span><br><span class="line">       <span class="comment">//通过while循环，判断正序和倒序的字母</span></span><br><span class="line">       <span class="keyword">while</span> (start &lt; end) &#123;</span><br><span class="line">         <span class="comment">// 如果相等则更改比较的索引</span></span><br><span class="line">         <span class="keyword">if</span> (str[start] === str[end]) &#123;</span><br><span class="line">           start++;</span><br><span class="line">           end--;</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> str = <span class="string">&quot;abcdcba&quot;</span>;</span><br></pre></td></tr></table></figure>

<p><strong>算法2</strong></p>
<p>思想：将字符串进行逆序的处理，然后与原来的字符串进行比较，如果相等则表示是回文字符串，否则不是回文字符串。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">isEequStr</span>(<span class="params">str</span>) &#123;</span><br><span class="line">        <span class="comment">//字符串统一转换成小写的形式</span></span><br><span class="line">        str = str.<span class="title function_">toLowerCase</span>();</span><br><span class="line">        <span class="comment">//将字符串转换成数组</span></span><br><span class="line">        <span class="keyword">var</span> arr = str.<span class="title function_">split</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">        <span class="comment">//将数组逆序并转换成字符串</span></span><br><span class="line">        <span class="keyword">var</span> reverseStr = arr.<span class="title function_">reverse</span>().<span class="title function_">join</span>(<span class="string">&quot;&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> str === reverseStr;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isEequStr</span>(<span class="string">&quot;abccba&quot;</span>));</span><br></pre></td></tr></table></figure>

<h2 id="2、运算符"><a href="#2、运算符" class="headerlink" title="2、运算符"></a>2、运算符</h2><p>在<code>JavaScript</code>中的运算符包括：算术运算符，关系运算符，等于运算符，位运算符(与、或、非)等</p>
<h3 id="2-1-等于运算符"><a href="#2-1-等于运算符" class="headerlink" title="2.1 等于运算符"></a>2.1 等于运算符</h3><p>在<code>JavaScript</code>中等于分为双等(&#x3D;&#x3D;)比较，和三等于(&#x3D;&#x3D;&#x3D;)比较。</p>
<h4 id="2-1-1-三等于运算符"><a href="#2-1-1-三等于运算符" class="headerlink" title="2.1.1 三等于运算符"></a>2.1.1 三等于运算符</h4><p>(1)如果比较的值类型不相同，则直接返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="number">1</span>===<span class="string">&#x27;1&#x27;</span> <span class="comment">//false</span></span><br><span class="line"><span class="literal">true</span>===<span class="string">&#x27;true&#x27;</span> <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>这里还需要注意的一点就是，基本数据类型存在包装类型，在没有使用<code>new</code>操作符时，简单类型的比较实际上就是值的比较，而使用了<code>new</code>操作符以后，实际得到的是引用类型的值，在判断时会因为类型不同而直接返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="number">1</span>===<span class="title class_">Number</span>(<span class="number">1</span>) <span class="comment">//true </span></span><br><span class="line"><span class="number">1</span>===<span class="keyword">new</span> <span class="title class_">Number</span>(<span class="number">1</span>) <span class="comment">//false</span></span><br><span class="line"><span class="string">&#x27;hello&#x27;</span>===<span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>) <span class="comment">//true</span></span><br><span class="line"><span class="string">&#x27;hello&#x27;</span>===<span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>) <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>(2) 如果比较的值都是数值类型，则直接比较值的大小，相等则返回<code>true</code>,否则返回<code>false</code>,需要注意的是，如果参与比较的值中有任何一方为<code>NaN</code>,则返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="number">26</span>===<span class="number">26</span> <span class="comment">//true</span></span><br><span class="line"><span class="number">34</span>===<span class="title class_">NaN</span> <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>（3）如果比较的值是字符串类型，则判断每个字符是否相等，如果全部相等，返回<code>true</code>,否则返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">&#x27;abc&#x27;</span>===<span class="string">&#x27;abc&#x27;</span> <span class="comment">//true</span></span><br><span class="line"><span class="string">&#x27;abc&#x27;</span>===<span class="string">&#x27;abd&#x27;</span> <span class="comment">//false</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>（4）关于<code>null</code>与<code>undefined</code>比较</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="literal">null</span>===<span class="literal">null</span> <span class="comment">//true</span></span><br><span class="line"><span class="literal">undefined</span>===<span class="literal">undefined</span> <span class="comment">//true</span></span><br><span class="line"><span class="literal">undefined</span>===<span class="literal">null</span> <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>(5)如果比较的值都是引用类型，则比较的是引用类型的地址，当两个引用指向同一个地址时，则返回<code>true</code>,否则返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a=[]</span><br><span class="line"><span class="keyword">var</span> b=a</span><br><span class="line"><span class="keyword">var</span> c=[]</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a===b) <span class="comment">//true</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a===c) <span class="comment">//false</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>)===<span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;hello&#x27;</span>)<span class="comment">//false 两个不同对象，地址不相同</span></span><br><span class="line"><span class="comment">//创建构造函数</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;wangwu&quot;</span>);</span><br><span class="line">     <span class="keyword">var</span> p2 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;wangwu&quot;</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(p1 === p2);<span class="comment">//false  两个不同对象，地址不相同</span></span><br></pre></td></tr></table></figure>

<h4 id="2-1-2-双等于运算符"><a href="#2-1-2-双等于运算符" class="headerlink" title="2.1.2 双等于运算符"></a>2.1.2 双等于运算符</h4><p>相比于三等于运算符，双等于运算符在进行相等比较的时候，要复杂一点。因为它不区分数据类型，而且会做隐式类型的转换。</p>
<p>双等于在进行比较的时候要注意的点：</p>
<p>如果比较的值类型不相同，则会按照下面的规则进行转换后再进行比较</p>
<p>(1) 如果比较的一方是<code>null</code>或者是<code>undefined</code>,只有在另一方是<code>null</code>或者是<code>undefined</code>的情况下才返回<code>true</code>,否则返回<code>false</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="literal">null</span>==<span class="literal">undefined</span> <span class="comment">//true</span></span><br><span class="line"><span class="literal">null</span>==<span class="number">1</span> <span class="comment">//false</span></span><br><span class="line"><span class="literal">undefined</span>==<span class="number">2</span> <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>（2）如果比较的是字符串和数值类型数据，则会将字符串转换为数值后再进行比较，如果转换后的数值是相等的则返回<code>true</code>,否则返回<code>false</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="number">1</span>==<span class="string">&#x27;1&#x27;</span> <span class="comment">//true</span></span><br><span class="line"><span class="string">&#x27;222&#x27;</span>==<span class="number">222</span> <span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>（3）如果比较的时候，有一方的类型是<code>boolean</code>类型，会将<code>boolean</code>类型进行转换，<code>true</code>转换为1,<code>false</code>转换0，然后在进行比较。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="string">&#x27;1&#x27;</span>==<span class="literal">true</span></span><br><span class="line"><span class="string">&#x27;2&#x27;</span>==<span class="literal">true</span> <span class="comment">//false</span></span><br><span class="line"><span class="string">&#x27;0&#x27;</span>==<span class="literal">false</span> <span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<h3 id="2-2-typeof运算符"><a href="#2-2-typeof运算符" class="headerlink" title="2.2 typeof运算符"></a>2.2 typeof运算符</h3><p><code>typeof</code>运算符用于返回对应的数据类型，</p>
<p>基本的使用方式</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">typeof operator</span><br><span class="line">typeof (operator)</span><br></pre></td></tr></table></figure>

<p><code>operator</code>表示要返回类型的操作数，可以是引用类型，也可以是基本数据类型。</p>
<p>括号有时候是必须的，如果不加上括号将会因为优先级的问题，而得不到我们想要的结果。</p>
<p>下面我们看一下<code>typeof</code>的使用场景</p>
<p>（1）处理<code>Undefined</code>类型</p>
<p>我们知道<code>Undefined</code>类型的值只有一个<code>undefined</code>,<code>typeof</code>运算符在处理如下情况的时候，返回的结果都是<code>undefined</code></p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">处理undefined本身</span><br><span class="line">未声明的变量</span><br><span class="line">已经声明但是没有初始化的变量</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="literal">undefined</span> <span class="comment">//&quot;undefined&quot;</span></span><br><span class="line"><span class="keyword">typeof</span> abc <span class="comment">//&quot;undefined&quot; ,未声明的变量abc，通过typeof返回的是undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> sum</span><br><span class="line"><span class="keyword">typeof</span> sum <span class="comment">//undefined  已经声明但是没有初始化的变量</span></span><br></pre></td></tr></table></figure>

<p>(2)处理<code>Boolean</code>类型的值</p>
<p><code>Boolean</code>类型的值有两个，分别是<code>true</code>和<code>false</code>,<code>typeof</code>运算符在处理这两个值的时候返回都是<code>boolean</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> b=<span class="literal">true</span></span><br><span class="line"><span class="keyword">typeof</span> b <span class="comment">//&quot;boolean&quot;</span></span><br></pre></td></tr></table></figure>

<p>(3) 处理<code>Number</code>类型的值</p>
<p>对于<code>Number</code>类型的数，<code>typeof</code>运算符在处理时会返回<code>number</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="number">666</span> <span class="comment">//number</span></span><br><span class="line"><span class="keyword">typeof</span> <span class="number">66.66</span> <span class="comment">//number</span></span><br></pre></td></tr></table></figure>

<p>（4）处理<code>String</code>类型的值</p>
<p>字符串类型，<code>typeof</code>返回的是<code>string</code>,包括空字符串。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="string">&#x27;aaa&#x27;</span> <span class="comment">//string</span></span><br><span class="line"><span class="keyword">typeof</span> <span class="string">&#x27;&#x27;</span> <span class="comment">//string</span></span><br></pre></td></tr></table></figure>

<p>(5)处理<code>Function</code>类型的值</p>
<p>函数的定义，包括函数的声明，<code>typeof</code>返回的值<code>function</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fun</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">typeof</span> fun <span class="comment">// &quot;function&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fun2=<span class="keyword">function</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">typeof</span> fun2 <span class="comment">// &quot;function&quot;</span></span><br></pre></td></tr></table></figure>

<p>关于通过<code>class</code>关键字定义的类，通过<code>typoef</code>计算返回的值也是<code>function</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Obj</span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">typeof</span> <span class="title class_">Obj</span> <span class="comment">// &quot;function&quot;</span></span><br></pre></td></tr></table></figure>

<p><code>class</code>是在<code>ES6</code>中新增的一个关键字，原理依旧是原型继承，也就是说本质上仍然是一个<code>Function</code></p>
<p>(6) 处理<code>Object</code>类型的值</p>
<p>对象字面量的形式，返回的是<code>object</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj=&#123;<span class="attr">userName</span>:<span class="string">&#x27;zhangsan&#x27;</span>&#125;</span><br><span class="line"><span class="keyword">typeof</span> obj <span class="comment">//&quot;object&quot;</span></span><br></pre></td></tr></table></figure>

<p>数组，通过<code>typeof</code>计算返回的值是<code>object</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr=[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line"><span class="keyword">typeof</span> arr <span class="comment">// &quot;object&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> arr2=<span class="keyword">new</span> <span class="title class_">Array</span>()</span><br><span class="line"><span class="keyword">typeof</span> arr2 <span class="comment">//&quot;object&quot;</span></span><br></pre></td></tr></table></figure>

<p>(7) <code>typeof</code>运算符对<code>null</code>的处理</p>
<p><code>typeof</code>运算符对<code>null</code>的处理，返回的是<code>object</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="literal">null</span> <span class="comment">//object</span></span><br></pre></td></tr></table></figure>

<p>注意：在前面我们提到过，在使用<code>typeof</code>的时候，括号有时候是必须的，如果不加上括号会因为优先级问题，得不到我们想要的结果。</p>
<p>例如如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num=<span class="number">123</span></span><br><span class="line"><span class="keyword">typeof</span> (num + <span class="string">&#x27;hello&#x27;</span>)<span class="comment">// string</span></span><br><span class="line"><span class="keyword">typeof</span> num + <span class="string">&quot; hello&quot;</span>  <span class="comment">//&quot;number hello&quot;</span></span><br></pre></td></tr></table></figure>

<p>通过上面的代码，我们知道<code>typeof</code>运算符的优先级要高于字符串的拼接运算符<code>(+)</code>,但是优先级低于小括号，所以在未使用括号时，会优先处理<code>typeof num</code>, 返回的是<code>number</code>,然后与<code>hello</code>字符串进行拼接，得到的最终的结果就是<code>number hello</code></p>
<p>下面，我们再来看一段代码</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> <span class="number">6</span>/<span class="number">2</span> <span class="comment">// NaN</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，会先执行<code>typeof 6</code> 得到的结果为<code>number</code>,然后除以2，一个字符串除以2，得到的结果为<code>NaN</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typeof</span> (<span class="number">6</span>/<span class="number">2</span>) <span class="comment">//&quot;number&quot;</span></span><br></pre></td></tr></table></figure>

<p>这里会先计算括号中的内容，然后在通过<code>typeof</code>进行计算。</p>
<h2 id="3、常用的判空方法"><a href="#3、常用的判空方法" class="headerlink" title="3、常用的判空方法"></a>3、常用的判空方法</h2><p>在<code>JavaScript</code>中判断一个变量是否为空，我们往往会想到对变量取反，然后判断是否为<code>true</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span>(!x)&#123; &#125;</span><br></pre></td></tr></table></figure>

<p>这是一个非常简单的判断变量是否为空的方法，但是其实涉及到的场景却很多，这里我们就分情况来看一下。</p>
<p><strong>（1）判断变量为空对象</strong></p>
<p> <strong>判断变量为<code>null</code>或者为<code>undefined</code></strong></p>
<p>判断一个变量是否为空时，可以直接将变量与<code>null</code>或者是<code>undefined</code>进行比较，需要注意的是双等号和三等好直接的区别。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span>(obj==<span class="literal">null</span>) <span class="comment">//可以判断null或者是undefined的情况</span></span><br><span class="line"><span class="keyword">if</span>(obj===<span class="literal">undefined</span>) <span class="comment">//只能判断undefined的情况    </span></span><br></pre></td></tr></table></figure>

<p><strong>判断变量为空对象<code>&#123; &#125;</code></strong></p>
<p>判断一个变量是否为空对象时，可以通过<code>for...in</code>语句遍历变量的属性，然后调用<code>hasOwnProperty( )</code>函数，判断是否有自身存在的属性，如果存在就不是空对象，如果不存在自身的属性（不包括继承的属性），那么变量为空对象。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">isEmpty</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">          <span class="keyword">if</span> (obj.<span class="title function_">hasOwnProperty</span>(key)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> obj = &#123;</span><br><span class="line">        <span class="attr">username</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isEmpty</span>(obj));<span class="comment">// false,表明obj这个对象是有自己的属性，所以不是空对象</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;&#125;;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isEmpty</span>(obj));<span class="comment">//true,这里将obj对象的属性去掉了，返回的值为true,表明没有自己的属性，表示空对象</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//这里通过构造函数的形式创建对象，并且指定了age属性</span></span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = <span class="number">20</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isEmpty</span>(p));<span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>下面看一下另外一种情况</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">userName</span> = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">      <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isEmpty</span>(p)); <span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，变量<code>p</code>是通过<code>new</code>操作符得到的<code>Person</code>对象的实例，所以<code>p</code>会继承<code>Person</code>原型链上的<code>userName</code>属性，但是因为不是自身的属性，所以会被判断为空，所以返回<code>true</code>.</p>
<p><strong>(2)判断变量为空数组</strong></p>
<p>判断变量是否为空数组时，首先要判断变量是否为数组，然后通过数组的<code>length</code>属性确定。(<strong><code>instanceof</code> 用于判断一个变量是否某个对象的实例</strong>)</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr=<span class="keyword">new</span> <span class="title class_">Array</span>()</span><br><span class="line">arr <span class="keyword">instanceof</span> <span class="title class_">Array</span> &amp;&amp; arr.<span class="property">length</span>===<span class="number">0</span></span><br></pre></td></tr></table></figure>

<p>以上两个条件都满足时，变量就是一个空数组。</p>
<p><strong>(3) 判断变量为空字符串</strong></p>
<p>判断变量是否为空字符串时，可以直接将其与空字符串进行比较，或者调用<code>trim()</code>函数去掉前后的空格以后，在去判断字符串的长度。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">str==<span class="string">&#x27;&#x27;</span>||str.<span class="title function_">trim</span>().<span class="property">length</span>==<span class="number">0</span></span><br></pre></td></tr></table></figure>

<p>当满足以上两个条件中的任意一个时，变量就是一个空字符串。</p>
<p><strong>（4）判断变量为0或者<code>NaN</code></strong></p>
<p>当一个变量为<code>Number</code>类型时，判断变量是否为0或者<code>NaN</code>,因为<code>NaN</code>与任何值比较都是<code>false</code>,所以这里我们通过取非来完成判断。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">!(<span class="title class_">Number</span>(num)&amp;&amp;num)==<span class="literal">true</span></span><br></pre></td></tr></table></figure>

<p>当上述代码返回的结果为<code>true</code>，表明变量为0或者是<code>NaN</code></p>
<p>（5）</p>
<p>在最开始的时候，我们提到的</p>
<p>在<code>JavaScript</code>中判断一个变量是否为空，我们往往会想到对变量取反，然后判断是否为<code>true</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span>(!x)&#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这种方式会包含多种情况，下面我们总结一下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">变量为<span class="literal">null</span></span><br><span class="line">变量为<span class="literal">undefined</span></span><br><span class="line">变量为空字符串<span class="string">&#x27;&#x27;</span></span><br><span class="line">变量为数字<span class="number">0</span></span><br><span class="line">变量为<span class="title class_">NaN</span></span><br></pre></td></tr></table></figure>

<h2 id="4、流程控制"><a href="#4、流程控制" class="headerlink" title="4、流程控制"></a>4、流程控制</h2><p>关于流程控制这块内容，这里我们重点看一下<code>Switch</code>结构</p>
<p>看一下如下代码执行的结果</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getStringValue</span>(<span class="params">str</span>) &#123;</span><br><span class="line">      <span class="keyword">switch</span> (str) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;1&quot;</span>:</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;a&quot;</span>);</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;2&quot;</span>:</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;b&quot;</span>);</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;3&quot;</span>:</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;c&quot;</span>);</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;d&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">getStringValue</span>(<span class="string">&quot;2&quot;</span>); <span class="comment">//b</span></span><br><span class="line">    <span class="title function_">getStringValue</span>(<span class="string">&quot;5&quot;</span>); <span class="comment">//d</span></span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>以上的代码非常简单。分别输出的是<code>b</code>和<code>d</code></p>
<p>但是，这里我们把对<code>getStringValue</code>函数的调用修改成如下的形式：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">getStringValue</span>(<span class="number">3</span>) <span class="comment">//d</span></span><br></pre></td></tr></table></figure>

<p>这里将参数修改成数字3，得到的结果是<code>d</code>.原因是：在<code>JavaScript</code>中的关于<code>case</code>的比较是采用严格相等的方式(&#x3D;&#x3D;&#x3D;)。在上面的函数调用中，传递的是数字类型的3，而在<code>case</code>中比较的是<code>String</code>字符串的’3’,两者按照严格方式进行对比，是不相等的。所以只能执行<code>default</code>,输出字母<code>d</code>.</p>
<p>下面，再来看如下的调用</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">getStringValue</span>(<span class="title class_">String</span>(<span class="string">&quot;3&quot;</span>)); <span class="comment">//c</span></span><br></pre></td></tr></table></figure>

<p>上面调用的结果是<code>c</code>.</p>
<p>在前面的课程中，我们讲解过：字符串的字面量和直接调用<code>String( )</code>函数生成的字符串都是基本的字符串，它们在本质上都是一样的。</p>
<p>所以在严格模式下进行比较是相等的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">String</span>(<span class="string">&#x27;3&#x27;</span>)===<span class="string">&#x27;3&#x27;</span> <span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>下面再来看另外一种调用方式</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">getStringValue</span>(<span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;3&quot;</span>)); <span class="comment">//d</span></span><br></pre></td></tr></table></figure>

<p>通过<code>new</code>关键字创建的是字符串对象，这里采用严格模式进行比较，比较的是字符串对象的内存地址是否相同。而当与字符串的字面量进行比较时，会返回<code>false</code>.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&#x27;3&#x27;</span>)===<span class="string">&#x27;3&#x27;</span> <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p>所以在运行整个<code>getStringValue</code>整个函数的时候，得到的结果为<code>d</code>.</p>
<h1 id="二、引用数据类型"><a href="#二、引用数据类型" class="headerlink" title="二、引用数据类型"></a>二、引用数据类型</h1><p>引用类型有<code>Object</code>,<code>Function</code>,<code>Array</code>,<code>Date</code>，<code>Math</code>等。</p>
<p>引用类型与基本数据类型的区别:</p>
<p>(1)引用数据类型的实例需要通过<code>new</code>关键字创建。</p>
<p>(2)将引用数据类型赋值给变量，实际上赋值的是内存地址</p>
<p>(3)引用数据类型的比较是对内存地址的比较，而基本数据类型的比较是对值的比较。</p>
<h2 id="1、Object类型"><a href="#1、Object类型" class="headerlink" title="1、Object类型"></a>1、Object类型</h2><p><code>Object</code>类型是<code>JavaScript</code>中使用最多的一个类型。</p>
<p>大部分的引用数据类型都是<code>Object</code>类型。</p>
<p>由于引用数据类型的实例都是通过<code>new</code>关键字来创建的，所以我们先来探讨有关<code>new</code>操作相关的问题。</p>
<h3 id="1-1-new-操作符的作用"><a href="#1-1-new-操作符的作用" class="headerlink" title="1.1  new 操作符的作用"></a>1.1  new 操作符的作用</h3><p><code>new</code>操作符在执行过程中会改变<code>this</code>的指向，所以下面我们先来看一下<code>this</code>的用法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, age</span>) &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>));</span><br><span class="line"> &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>执行上面的代码，发现输出的是一个<code>Person</code>对象，包含了<code>userName</code>和<code>age</code>的数据。</p>
<p>但是，问题是，在构造函数<code>Person</code>中，我们没有添加<code>return</code>,为什么会有返回值呢？</p>
<p>其实就是<code>this</code>这个关键字起作用。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, age</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);<span class="comment">//输出的是Person&#123; &#125;对象</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>);</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>执行上面的代码，我们可以看到<code>this</code> 这里就是一个<code>Person</code>的空对象，后面的两行代码就相当于给<code>Person</code>对象添加了<code>userName</code>和<code>age</code>这两个属性。</p>
<p>下面我们把代码修改成如下的形式：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, age</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> <span class="title class_">Person</span> = &#123;&#125;;</span><br><span class="line">       <span class="title class_">Person</span>.<span class="property">userName</span> = userName;</span><br><span class="line">       <span class="title class_">Person</span>.<span class="property">age</span> = age;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>));</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>以上打印的结果中，输出的是<code>Person&#123;&#125;</code>，并没有包含<code>userName</code>和<code>age</code>,原因是什么呢？</p>
<p>因为在 构造函数中如果没有添加<code>return</code>,则默认返回的是<code>return this</code>.</p>
<p>修改后的代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, age</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> <span class="title class_">Person</span> = &#123;&#125;;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property">userName</span> = userName;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property">age</span> = age;</span><br><span class="line">      <span class="keyword">return</span> <span class="title class_">Person</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>));</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>对<code>this</code>有了一个简单的了解以后，下面重点看如下代码</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person= <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>)</span><br></pre></td></tr></table></figure>

<p>从上面的代码中，主要的作用就是创建一个<code>Person</code>对象，然后赋值给了<code>person</code>这个变量，该变量中包含了<code>Person</code>对象中的属性和函数。</p>
<p>其实，在<code>new</code>操作符做了如下3件事情。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person=&#123;&#125;; <span class="comment">// 创建一个空对象</span></span><br><span class="line">person.<span class="property">__proto__</span>=<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>; <span class="comment">// 将__proto__属性绑定到原型链上</span></span><br><span class="line"><span class="title class_">Person</span>.<span class="title function_">call</span>(person) <span class="comment">// 将this指向新对象</span></span><br></pre></td></tr></table></figure>



<h3 id="1-2-原型对象理解"><a href="#1-2-原型对象理解" class="headerlink" title="1.2 原型对象理解"></a>1.2 原型对象理解</h3><h4 id="函数对象的-prototype-属性"><a href="#函数对象的-prototype-属性" class="headerlink" title="函数对象的 prototype 属性"></a>函数对象的 prototype 属性</h4><p>我们创建的每一个函数都有一个 <code>prototype</code> 属性，这个属性是一个指针，指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法，简单来说，该函数实例化的所有对象的<code>__proto__</code>的属性指向这个对象，它是该函数所有实例化对象的原型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>)&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 为原型对象添加方法</span></span><br><span class="line"><span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayName</span> = <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="title function_">alert</span>(<span class="variable language_">this</span>.<span class="property">name</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面我们来看一下它们之间的关系。</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/prototype.png"></p>
<p><strong>简易图</strong></p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2%5C%E7%AE%80%E6%98%93prototype.png"></p>
<h4 id="constructor-属性"><a href="#constructor-属性" class="headerlink" title="constructor 属性"></a>constructor 属性</h4><p>当函数创建，<code>prototype </code>属性指向一个原型对象时，在默认情况下，这个原型对象将会获得一个 constructor 属性，这个属性是一个指针，指向 <code>prototype</code> 所在的函数对象。</p>
<p>拿前面的一个例子来说 <code>Person.prototype.constructor</code> 就指向 <code>Person </code>函数对象。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> == <span class="title class_">Person</span>) </span><br></pre></td></tr></table></figure>

<p>下面我们来更新一下它们之间的关系图。</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2%5Cconstructor.png"></p>
<pre><code>  **简易图**
</code></pre>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2%5Cconstructor.jpg"></p>
<h4 id="对象的-proto-属性"><a href="#对象的-proto-属性" class="headerlink" title="对象的 __proto__ 属性"></a>对象的 <code>__proto__ </code>属性</h4><p>当我们调用构造函数创建一个新实例后，在这个实例的内部将包含一个指针，指向构造函数的原型对象.</p>
<p>根据前面的 <code>Person</code> 构造函数我们新建一个实例</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="property">__proto__</span> === <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>); <span class="comment">// true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>从上面我们可以看出，这个连接是存在与实例与构造函数的原型对象之间的，而不是存在于实例和构造函数之间的。 </p>
<p>下面我们来看一下现在这几个对象之间的关系</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/proto.png"></p>
<p><code>isPrototypeOf()</code> 方法用于测试一个对象是否存在于另一个对象的原型链上。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="title function_">isPrototypeOf</span>(student)); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>

<p><strong>简易图</strong></p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2%5Cproto.jpg"></p>
<h3 id="1-3-原型属性"><a href="#1-3-原型属性" class="headerlink" title="1.3 原型属性"></a>1.3 原型属性</h3><h5 id="属性访问"><a href="#属性访问" class="headerlink" title="属性访问"></a>属性访问</h5><p>每当代码读取对象的某个属性时，首先会在对象本身搜索这个属性，如果找到该属性就返回该属性的值，如果没有找到，则继续搜索该对象对应的原型对象，以此类推下去。</p>
<p>因为这样的搜索过程，因此我们如果在实例中添加一个属性时，这个属性就会屏蔽原型对象中保存的同名属性，因为在实例中搜索到该属性后就不会再向后搜索了。</p>
<h5 id="属性判断"><a href="#属性判断" class="headerlink" title="属性判断"></a>属性判断</h5><p>既然一个属性既可能是实例本身的，也有可能是其原型对象的，那么我们该如何来判断呢？</p>
<p>在属性确认存在的情况下，我们可以使用 <code>hasOwnProperty() </code>方法来判断一个属性是存在与实例中，还是存在于原型中</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">name</span> = <span class="string">&quot;laker&quot;</span> ;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="property">name</span>); <span class="comment">// laker</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="title function_">hasOwnProperty</span>(<span class="string">&quot;name&quot;</span>)); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">student.<span class="property">name</span> = <span class="string">&quot;xiaoming&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="property">name</span>); <span class="comment">//xiaoming 屏蔽了原型对象中的 name 属性</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="title function_">hasOwnProperty</span>(<span class="string">&quot;name&quot;</span>)); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">hasPrototypeProperty</span>(<span class="params">object, name</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> !object.<span class="title function_">hasOwnProperty</span>(name) &amp;&amp; (name <span class="keyword">in</span> object);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h5 id="所有属性获取"><a href="#所有属性获取" class="headerlink" title="所有属性获取"></a>所有属性获取</h5><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">  <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&quot;KXY&quot;</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">        <span class="attr">job</span>: <span class="string">&quot;student&quot;</span>,</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> kxy = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(kxy, <span class="string">&quot;sex&quot;</span>, &#123;</span><br><span class="line">        <span class="attr">value</span>: <span class="string">&quot;female&quot;</span>,</span><br><span class="line">        <span class="attr">enumerable</span>: <span class="literal">false</span>,</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">keys</span>(kxy)); <span class="comment">//[&quot;name&quot;] //无法获取不可枚举的属性与原型链上继承的属性</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">getOwnPropertyNames</span>(kxy));<span class="comment">//[&quot;name&quot;, &quot;sex&quot;]</span></span><br><span class="line"><span class="comment">//for...in能获取原型链上继承的属性，无法获取不可枚举的属性</span></span><br><span class="line"> 	<span class="keyword">for</span> (<span class="keyword">var</span> pro <span class="keyword">in</span> kxy) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;kxy.&quot;</span> + pro + <span class="string">&quot; = &quot;</span> + kxy[pro]);<span class="comment">// kxy.name = KXY</span></span><br><span class="line">        <span class="comment">//kxy.job = student</span></span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>



<p><strong>怎样判断属性是否为实例属性并且是否可枚举</strong></p>
<p>如果想判断指定名称的属性是否为实例属性并且是否可枚举的，可以使用<code>propertyIsEnumerable</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Student</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHello</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span> + <span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">var</span> stu = <span class="keyword">new</span> <span class="title class_">Student</span>();</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stu.<span class="title function_">propertyIsEnumerable</span>(<span class="string">&quot;userName&quot;</span>)); <span class="comment">//true:userName为自身定义的实例属性</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stu.<span class="title function_">propertyIsEnumerable</span>(<span class="string">&quot;age&quot;</span>)); <span class="comment">// false:age属性不存在，返回false</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stu.<span class="title function_">propertyIsEnumerable</span>(<span class="string">&quot;sayHello&quot;</span>)); <span class="comment">// false :sayHello属于原型上的函数</span></span><br><span class="line">     <span class="comment">//将userName属性设置为不可枚举</span></span><br><span class="line">     <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(stu, <span class="string">&quot;userName&quot;</span>, &#123;</span><br><span class="line">       <span class="attr">enumerable</span>: <span class="literal">false</span>,</span><br><span class="line">     &#125;);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stu.<span class="title function_">propertyIsEnumerable</span>(<span class="string">&quot;userName&quot;</span>)); <span class="comment">// false: userName设置了不可枚举</span></span><br></pre></td></tr></table></figure>

<h3 id="1-4-Object-create-方法"><a href="#1-4-Object-create-方法" class="headerlink" title="1.4 Object.create( )方法"></a>1.4 <code>Object.create( )</code>方法</h3><h4 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h4><p>该函数的主要作用是创建并返回一个指定原型和指定属性的新对象，语法格式如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Object</span>.<span class="title function_">create</span>(prototype,propertyDescriptor)</span><br></pre></td></tr></table></figure>

<p><code>prototype</code>属性为对象的原型（必须），可以为<code>null</code>,如果为<code>null</code>，则对象的原型为<code>undefined</code>.</p>
<p><code>propertyDescriptor</code>表示的是属性描述符（可选），具体的格式如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="attr">propertyName</span>:&#123;</span><br><span class="line">    <span class="attr">value</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">writable</span>:<span class="literal">true</span>,</span><br><span class="line">    <span class="attr">enumerable</span>:<span class="literal">true</span>,</span><br><span class="line">    <span class="attr">configurable</span>:<span class="literal">true</span> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>基本实现：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script type=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><br><span class="line">     <span class="keyword">const</span> person = &#123;</span><br><span class="line">       <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">       <span class="attr">sayHello</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello &quot;</span> + <span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">const</span> stu = <span class="title class_">Object</span>.<span class="title function_">create</span>(person);</span><br><span class="line">     stu.<span class="property">userName</span> = <span class="string">&quot;lisi&quot;</span>;</span><br><span class="line">     stu.<span class="title function_">sayHello</span>(); <span class="comment">//hello lisi  覆盖了person中的userName属性原有的值</span></span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，可以看到<code>stu</code>对象的原型是<code>person</code>.也就是<code>stu.__proto__===person</code></p>
<p>下面再来看一个案例：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="literal">null</span>, &#123;</span><br><span class="line">        <span class="attr">userName</span>: &#123;</span><br><span class="line">          <span class="attr">value</span>: <span class="string">&quot;wangwu&quot;</span>,</span><br><span class="line">          <span class="attr">writable</span>: <span class="literal">true</span>,</span><br><span class="line">          <span class="attr">enumerable</span>: <span class="literal">true</span>,</span><br><span class="line">          <span class="attr">configurable</span>: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">age</span>: &#123;</span><br><span class="line">          <span class="attr">value</span>: <span class="number">23</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">userName</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">age</span>); </span><br><span class="line">      obj.<span class="property">age</span> = <span class="number">26</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">age</span>); </span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> o <span class="keyword">in</span> obj) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(o);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">delete</span> obj.<span class="property">userName</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">userName</span>); </span><br><span class="line">      <span class="keyword">delete</span> obj.<span class="property">age</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">age</span>); </span><br></pre></td></tr></table></figure>



<h4 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h4><p>通过如下的伪代码来查看对应的实现原理</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Object</span>.<span class="property">create</span>=<span class="keyword">function</span>(<span class="params">proto,propertiesObject</span>)&#123;</span><br><span class="line">    <span class="comment">//省略了其它判断操作</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">F</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">    F.<span class="property"><span class="keyword">prototype</span></span>=proto;</span><br><span class="line">    <span class="keyword">if</span>(propertiesObject)&#123; <span class="title class_">Object</span>.<span class="title function_">defineProperties</span>(F, propertiesObject)&#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title function_">F</span>()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>通过以上的代码，我们可以得出如下的结论：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> f=<span class="keyword">new</span> <span class="title function_">F</span>()</span><br><span class="line">f.<span class="property">__proto__</span>===F.<span class="property"><span class="keyword">prototype</span></span></span><br></pre></td></tr></table></figure>

<p>下面我们可以通过一个例子来验证一下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123; <span class="attr">x</span>: <span class="number">12</span>, <span class="attr">y</span>: <span class="number">13</span> &#125;;</span><br><span class="line">     <span class="keyword">var</span> test = <span class="title class_">Object</span>.<span class="title function_">create</span>(obj);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(test); </span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(test.<span class="property">x</span>); </span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(test.<span class="property">__proto__</span>.<span class="property">x</span>);</span><br></pre></td></tr></table></figure>



<p><strong>最后，这里演示一下<code>Object.defineProperties</code>方法的基本使用</strong></p>
<p>该方法的主要作用就是添加或修改对象的属性。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123;&#125;;</span><br><span class="line">     </span><br><span class="line">      <span class="title class_">Object</span>.<span class="title function_">defineProperties</span>(person, &#123;</span><br><span class="line">        <span class="attr">userName</span>: &#123;</span><br><span class="line">          <span class="attr">value</span>: <span class="string">&quot;张三&quot;</span>,</span><br><span class="line">          <span class="attr">enumerable</span>: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">age</span>: &#123;</span><br><span class="line">          <span class="attr">value</span>: <span class="number">12</span>,</span><br><span class="line">          <span class="attr">enumerable</span>: <span class="literal">true</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> p <span class="keyword">in</span> person) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(p); </span><br><span class="line">      &#125;</span><br><span class="line">      person.<span class="property">age</span> = <span class="number">20</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">age</span>); </span><br></pre></td></tr></table></figure>



<h4 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h4><p>对于<code>Object.create</code>方法很重要的一个应用场景是用来实现继承</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, sex</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">sex</span> = sex;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getInfo</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;getInfo: [name:&quot;</span> + <span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;, sex:&quot;</span> + <span class="variable language_">this</span>.<span class="property">sex</span> + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> a = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;jojo&quot;</span>, <span class="string">&quot;femal&quot;</span>);</span><br><span class="line">      <span class="keyword">var</span> b = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a.<span class="property">name</span>); </span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(b.<span class="property">name</span>); </span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(b.<span class="property">getInfo</span>); </span><br></pre></td></tr></table></figure>



<p>下面看一下怎样实现完整的继承操作。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, sex</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">sex</span> = sex;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getInfo</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;getInfo: [name:&quot;</span> + <span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;, sex:&quot;</span> + <span class="variable language_">this</span>.<span class="property">sex</span> + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Student</span>(<span class="params">name, sex, age</span>) &#123;</span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, name, sex); </span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>); </span><br><span class="line">      <span class="keyword">var</span> s = <span class="keyword">new</span> <span class="title class_">Student</span>(<span class="string">&quot;coco&quot;</span>, <span class="string">&quot;femal&quot;</span>, <span class="number">25</span>);</span><br><span class="line">      s.<span class="title function_">getInfo</span>();</span><br></pre></td></tr></table></figure>

<p>下面，我们简单的分析一下，上面的代码。</p>
<p>对象<code>s</code>的<code>__proto__</code>指向的是<code>s</code>的构造函数<code>Student</code>的<code>prototype</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">s.<span class="property">__proto__</span>===<span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span> </span><br></pre></td></tr></table></figure>

<p>那么<code>Student.prototype</code>的<code>__proto__</code>指向什么呢？</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span>===<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> </span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">s.<span class="property">__proto__</span>.<span class="property">__proto__</span>===<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> </span><br></pre></td></tr></table></figure>



<p>而我们知道对象<code>s</code>是有<code>Student</code> 创建的，所以其构造函数为<code>Student</code>,所以我们在修改了原型以后，这里应该重新修正构造函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, sex</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">sex</span> = sex;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getInfo</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;getInfo: [name:&quot;</span> + <span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;, sex:&quot;</span> + <span class="variable language_">this</span>.<span class="property">sex</span> + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Student</span>(<span class="params">name, sex, age</span>) &#123;</span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, name, sex); </span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="title class_">Object</span>.<span class="title function_">create</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>);</span><br><span class="line">      <span class="title class_">Student</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Student</span>;     </span><br><span class="line">      <span class="keyword">var</span> s = <span class="keyword">new</span> <span class="title class_">Student</span>(<span class="string">&quot;coco&quot;</span>, <span class="string">&quot;femal&quot;</span>, <span class="number">25</span>);</span><br><span class="line">      s.<span class="title function_">getInfo</span>();</span><br></pre></td></tr></table></figure>

<h3 id="1-5-Object-create-与new-Object-的区别"><a href="#1-5-Object-create-与new-Object-的区别" class="headerlink" title="1.5 Object.create( )与new Object()的区别"></a>1.5 <code>Object.create( )</code>与<code>new Object()</code>的区别</h3><h3 id="1-6-模拟new操作符的实现"><a href="#1-6-模拟new操作符的实现" class="headerlink" title="1.6 模拟new操作符的实现"></a>1.6 模拟<code>new</code>操作符的实现</h3><p>在前面我们介绍了<code>new</code>操作符所做的三件事情，下面我们来模拟实现一下。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, age</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">New</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> obj = &#123;&#125;;</span><br><span class="line">           <span class="keyword">var</span> res = <span class="title class_">Person</span>.<span class="title function_">apply</span>(obj, <span class="variable language_">arguments</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">typeof</span> res === <span class="string">&quot;object&quot;</span> ? res : obj;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">New</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">19</span>));</span><br></pre></td></tr></table></figure>



<h3 id="1-7-原型链理解"><a href="#1-7-原型链理解" class="headerlink" title="1.7 原型链理解"></a>1.7 原型链理解</h3><p>下面我们通过一个案例来看一个简单的原型链过程。初步代码如下</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> A=<span class="keyword">function</span>(<span class="params"></span>)&#123; &#125;</span><br><span class="line"><span class="keyword">var</span> a=<span class="keyword">new</span> <span class="title function_">A</span>( );</span><br></pre></td></tr></table></figure>

<p>通过<code>a</code> 实例沿着原型链第一次的追溯，<code>__proto__</code>属性指向<code>A()</code>构造函数的原型对象。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">a.<span class="property">__proto__</span>===A.<span class="property"><span class="keyword">prototype</span></span> </span><br></pre></td></tr></table></figure>

<p><code>a</code>实例沿着原型链第二次的追溯，<code>A</code>原型对象的<code>__proto__</code>属性指向<code>Object</code>类型的原型对象.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">a.<span class="property">__proto__</span>.<span class="property">__proto__</span>===A.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span> </span><br><span class="line">A.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span>===<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span></span><br></pre></td></tr></table></figure>

<p><code>a</code> 实例沿着原型链第三次追溯，<code>Object</code>类型的原型对象的<code>__proto__</code>属性为<code>null</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">a.<span class="property">__proto__</span>.<span class="property">__proto__</span>.<span class="property">__proto__</span>===<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span></span><br><span class="line"><span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span>===<span class="literal">null</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>具体的图如下所示：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E9%93%BE1.png"></p>
<p>下面，我们再来看一个案例：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Super</span>(<span class="params"></span>)&#123;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Middle</span>(<span class="params"></span>)&#123;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Sub</span>(<span class="params"></span>)&#123;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Middle</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Super</span>();</span><br><span class="line"><span class="title class_">Sub</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Middle</span>();</span><br><span class="line"><span class="keyword">var</span> suber = <span class="keyword">new</span> <span class="title class_">Sub</span>();</span><br></pre></td></tr></table></figure>

<p>对应的原型链如下图所示：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E9%93%BE2.png"></p>
<p>上面的图其实并不完整，因为漏掉了<code>Object</code>.所以完整的图如下</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E9%93%BE3.png"></p>
<p>通过以上内容的讲解，我们对原型链有了更加深入的理解。</p>
<h3 id="1-8-原型链特点"><a href="#1-8-原型链特点" class="headerlink" title="1.8 原型链特点"></a>1.8 原型链特点</h3><p>关于原型链的特点，主要有两个</p>
<p>第一个特点：由于原型链的存在，属性查找的过程不再只是查找自身的原型对象，而是会沿着整个原型链一直向上，直到追溯到<code>Object.prototype</code>.也就是说，当<code>js</code>引擎在查找对象的属性时，先查找对象本身是否存在该属性，如果不存在，会在原型链上查找，直到<code>Object.prototype</code>.如果<code>Object.prototype</code>上也找不到该属性，则返回<code>undefined</code>,如果期间在对象本身找到了或者是某个原型对象上找到了该属性，则会返回对应的结果。</p>
<p>由于这个特点，我们在自定义的对象中，可以调用某些未在自定义构造函数中定义的函数，例如<code>toString( )</code>函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>)&#123; &#125;</span><br><span class="line"><span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">p.<span class="title function_">toString</span>(); <span class="comment">// 实际上调用的是Object.prototype.toString( )</span></span><br></pre></td></tr></table></figure>

<p>第二个特点：由于属性查找会经历整个原型链，因此查找的链路越长，对性能的影响越大。</p>
<h3 id="1-9-属性的区分"><a href="#1-9-属性的区分" class="headerlink" title="1.9 属性的区分"></a>1.9 属性的区分</h3><p>对象属性的查找往往会涉及到整个原型链，那么应该怎样区分属性是实例自身的还是从原型链中继承的呢？</p>
<p>关于这个问题，前面我们也已经讲解过，是通过<code>hasOwnProperty( )</code>函数来完成的，这里我们在简单的复习强调一下。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, age</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="comment">//在对象的原型上添加age属性</span></span><br><span class="line">     <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">age</span> = <span class="number">21</span>;</span><br><span class="line">     <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">hasOwnProperty</span>(<span class="string">&quot;name&quot;</span>)); <span class="comment">//true</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">hasOwnProperty</span>(<span class="string">&quot;age&quot;</span>)); <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<p><code>name</code>属性为实例属性，在调用<code>hasOwnProperty</code>方法时，会返回<code>true</code>。<code>age</code>属性为原型对象上的属性，在调用<code>hasOwnProperty</code>函数时，会返回<code>false</code>.</p>
<p>在使用<code>for...in</code>运算符，遍历对象的属性时，一般可以配合<code>hasOwnProperty</code>方法一起使用，检测某个属性是否为对象自身的属性，如果是，可以做相应的处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> p <span class="keyword">in</span> person)&#123;</span><br><span class="line">    <span class="keyword">if</span>(person.<span class="title function_">hasOwnProperty</span>(p))&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="2、Array类型"><a href="#2、Array类型" class="headerlink" title="2、Array类型"></a>2、Array类型</h2><p><code>Array</code>类型中提供了丰富的函数用于对数组进行处理，例如，过滤，去重，遍历等等操作。</p>
<h3 id="2-1-怎样-判断一个变量是数组还是对象"><a href="#2-1-怎样-判断一个变量是数组还是对象" class="headerlink" title="2.1 怎样 判断一个变量是数组还是对象"></a>2.1 怎样 判断一个变量是数组还是对象</h3><p>这里，我们可能会想到使用<code>typeof</code>运算符，因为<code>typeof</code>运算符是专门用于检测数据类型的，但是<code>typeof</code>运算符能够满足我们的需求吗？</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> a); </span><br></pre></td></tr></table></figure>



<h4 id="2-1-1-instanceof运算符"><a href="#2-1-1-instanceof运算符" class="headerlink" title="2.1.1 instanceof运算符"></a>2.1.1 <code>instanceof</code>运算符</h4><p><code>instanceof</code>运算符用于通过查找原型链来检查某个变量是否为某个类型数据的实例，使用<code>instanceof</code>运算符可以判断一个变量是数组还是对象。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">  <span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(a <span class="keyword">instanceof</span> <span class="title class_">Array</span>); <span class="comment">// true</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(a <span class="keyword">instanceof</span> <span class="title class_">Object</span>); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> userInfo = &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(userInfo <span class="keyword">instanceof</span> <span class="title class_">Array</span>); <span class="comment">// false</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(userInfo <span class="keyword">instanceof</span> <span class="title class_">Object</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>



<p>这里我们可以封装一个函数，用于判断变量是数组类型还是对象类型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">getType</span>(<span class="params">o</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (o <span class="keyword">instanceof</span> <span class="title class_">Array</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;Array&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (o <span class="keyword">instanceof</span> <span class="title class_">Object</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;Object&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;参数类型不是Array也不是Object&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getType</span>(a));</span><br></pre></td></tr></table></figure>



<h4 id="2-1-2-通过构造函数来判断"><a href="#2-1-2-通过构造函数来判断" class="headerlink" title="2.1.2  通过构造函数来判断"></a>2.1.2  通过构造函数来判断</h4><p>判断一个变量是否是数组还是对象，其实就是判断变量的构造函数是<code>Array</code>类型还是<code>Object</code>类型。</p>
<p>因为一个对象的实例都是通过构造函数创建的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(a.<span class="property">__proto__</span>.<span class="property">constructor</span> === <span class="title class_">Array</span>); </span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a.<span class="property">__proto__</span>.<span class="property">constructor</span> === <span class="title class_">Object</span>); <span class="comment">// false</span></span><br></pre></td></tr></table></figure>

<p>同样这里，这里我们也可以封装一个函数，来判断变量是数组类型还是对象类型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">getType</span>(<span class="params">o</span>) &#123;</span><br><span class="line">    <span class="comment">//获取构造函数</span></span><br><span class="line">    <span class="keyword">var</span> constructor = o.<span class="property">__proto__</span>.<span class="property">constructor</span>;</span><br><span class="line">    <span class="keyword">if</span> (constructor === <span class="title class_">Array</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;Array&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (constructor === <span class="title class_">Object</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;Object&quot;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">&quot;参数类型不是Array也不是Object&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getType</span>(a));</span><br></pre></td></tr></table></figure>



<h4 id="2-1-3-通过toString-函数来判断"><a href="#2-1-3-通过toString-函数来判断" class="headerlink" title="2.1.3 通过toString( )函数来判断"></a>2.1.3 通过<code>toString( )</code>函数来判断</h4><p>我们知道，每种引用类型都会直接或间接继承<code>Object</code>类型，因此它们都包含<code>toString( )</code>函数。</p>
<p>不同数据类型的<code>toString( )</code>函数返回值也不一样，所以通过<code>toString( )</code>函数就可以判断一个变量是数组还是对象，当然，这里我们需要用到<code>call</code>方法来调用<code>Object</code>原型上的<code>toString( )</code>函数来完成类型的判断。</p>
<p>如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"> <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">     <span class="keyword">var</span> obj = &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(arr)); <span class="comment">//[object Array]</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(obj)); <span class="comment">// [object Object]</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">toString</span>()); <span class="comment">// 1,2,3</span></span><br></pre></td></tr></table></figure>



<h4 id="2-1-4-通过Array-isArray-函数来判断"><a href="#2-1-4-通过Array-isArray-函数来判断" class="headerlink" title="2.1.4  通过Array.isArray( )函数来判断"></a>2.1.4  通过<code>Array.isArray( )</code>函数来判断</h4><p><code>Array.isArray</code> 方法用来判断变量是否为数组。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">  <span class="keyword">var</span> obj = &#123; <span class="attr">name</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">isArray</span>(<span class="number">1</span>)); <span class="comment">//false</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">isArray</span>(arr)); <span class="comment">//true</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">isArray</span>(obj)); <span class="comment">//false</span></span><br></pre></td></tr></table></figure>



<h3 id="2-2-怎样过滤数组中满足条件的数据"><a href="#2-2-怎样过滤数组中满足条件的数据" class="headerlink" title="2.2 怎样过滤数组中满足条件的数据"></a>2.2 怎样过滤数组中满足条件的数据</h3><p>对数组中的数据进行过滤，我们使用比较多的是<code>filter</code>方法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="keyword">var</span> fn = <span class="keyword">function</span> (<span class="params">x</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> x % <span class="number">2</span> !== <span class="number">0</span>;</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">78</span>, <span class="number">9</span>, <span class="number">10</span>];</span><br><span class="line">      <span class="keyword">var</span> result = arr.<span class="title function_">filter</span>(fn);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>下面，我们再来看一下针对复杂类型数组的过滤。</p>
<p>下面案例是查找出年龄大于16的男生的信息。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [</span><br><span class="line">       &#123; <span class="attr">gender</span>: <span class="string">&quot;男&quot;</span>, <span class="attr">age</span>: <span class="number">15</span> &#125;,</span><br><span class="line">       &#123; <span class="attr">gender</span>: <span class="string">&quot;男&quot;</span>, <span class="attr">age</span>: <span class="number">17</span> &#125;,</span><br><span class="line">       &#123; <span class="attr">gender</span>: <span class="string">&quot;女&quot;</span>, <span class="attr">age</span>: <span class="number">15</span> &#125;,</span><br><span class="line">     ];</span><br><span class="line">     <span class="keyword">var</span> fn = <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> obj.<span class="property">gender</span> === <span class="string">&quot;男&quot;</span> &amp;&amp; obj.<span class="property">age</span> &gt; <span class="number">16</span>;</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">const</span> result = arr.<span class="title function_">filter</span>(fn);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<h3 id="2-3-怎样对数组元素做累加处理"><a href="#2-3-怎样对数组元素做累加处理" class="headerlink" title="2.3 怎样对数组元素做累加处理"></a>2.3 怎样对数组元素做累加处理</h3><p>对数组中的元素做累加的处理，可以通过<code>reduce</code>函数来完成。</p>
<p><code>reduce</code>函数最主要的作用就是做累加的操作，该函数接收一个函数作为累加器，将数组中的每个元素从左到右依次执行累加器，返回最终的处理结果。</p>
<p><code>reduce</code>函数的语法如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">arr.<span class="title function_">reduce</span>(<span class="title function_">callback</span>(accumulator, currentValue[, index[, array]])[, initialValue])</span><br></pre></td></tr></table></figure>



<p>求出数组中所有元素累加的和</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">     <span class="keyword">var</span> sum = arr.<span class="title function_">reduce</span>(<span class="keyword">function</span> (<span class="params">accumulator, currentValue</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> accumulator + currentValue;</span><br><span class="line">     &#125;, <span class="number">0</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(sum);</span><br></pre></td></tr></table></figure>





<h3 id="2-4-怎样求数组中的最大值与最小值"><a href="#2-4-怎样求数组中的最大值与最小值" class="headerlink" title="2.4 怎样求数组中的最大值与最小值"></a>2.4 怎样求数组中的最大值与最小值</h3><p>关于查询出数组中的最大值与最小值的实现方式有很多种，下面我们来看一下具体的实现。</p>
<p>第一：通过<code>prototype</code>属性扩展<code>min</code>函数和<code>max</code>函数来实现求最小值与最大值</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//最小值</span></span><br><span class="line"> <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">min</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="keyword">var</span> min = <span class="variable language_">this</span>[<span class="number">0</span>];</span><br><span class="line">   <span class="keyword">var</span> len = <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">   <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i &lt; len; i++) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="variable language_">this</span>[i] &lt; min) &#123;</span><br><span class="line">       min = <span class="variable language_">this</span>[i];</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> min;</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="comment">//最大值</span></span><br><span class="line"> <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">max</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="keyword">var</span> max = <span class="variable language_">this</span>[<span class="number">0</span>];</span><br><span class="line">   <span class="keyword">var</span> len = <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">   <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i &lt; len; i++) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="variable language_">this</span>[i] &gt; max) &#123;</span><br><span class="line">       max = <span class="variable language_">this</span>[i];</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> max;</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">min</span>()); <span class="comment">// 1</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">max</span>()); <span class="comment">// 90</span></span><br></pre></td></tr></table></figure>

<p>第二：通过数组的<code>reduce</code>函数来完成。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">max</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">reduce</span>(<span class="keyword">function</span> (<span class="params">preValue, currentValue</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> preValue &gt; currentValue ? preValue : currentValue; <span class="comment">//返回最大的值</span></span><br><span class="line">   &#125;);</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">min</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">reduce</span>(<span class="keyword">function</span> (<span class="params">preValue, currentValue</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> preValue &lt; currentValue ? preValue : currentValue; <span class="comment">// 返回最小的值</span></span><br><span class="line">   &#125;);</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">min</span>()); <span class="comment">//</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(arr.<span class="title function_">max</span>()); <span class="comment">//</span></span><br></pre></td></tr></table></figure>

<p>第三：通过<code>ES6</code>中的扩展运算符来实现</p>
<p>这里我们可以通过<code>ES6</code>中的扩展运算符(…)来实现。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="title function_">min</span>(...arr)); <span class="comment">//</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="title function_">max</span>(...arr));</span><br></pre></td></tr></table></figure>

<h3 id="2-5-数组遍历的方式有哪些"><a href="#2-5-数组遍历的方式有哪些" class="headerlink" title="2.5 数组遍历的方式有哪些"></a>2.5 数组遍历的方式有哪些</h3><p>数组遍历是我们针对数组最频繁的操作。下面我们看一下常见的数组的遍历方式。</p>
<h4 id="通过for循环"><a href="#通过for循环" class="headerlink" title="通过for循环"></a>通过for循环</h4><p>这时最基本的实现方式</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr=[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;arr.<span class="property">length</span>;i++)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(arr[i])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="使用forEach-函数"><a href="#使用forEach-函数" class="headerlink" title="使用forEach( )函数"></a>使用<code>forEach( )</code>函数</h4><p><code>forEach</code>函数也是我们遍历数组用的比较多的方法，<code>forEach( )</code>函数接收一个回调函数，参数分别表示当前执行的元素的值，当前值的索引和数组本身。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">     arr.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(index + <span class="string">&quot;:&quot;</span> + element);</span><br><span class="line">     &#125;);</span><br></pre></td></tr></table></figure>

<h4 id="使用map-函数"><a href="#使用map-函数" class="headerlink" title="使用map( )函数"></a>使用<code>map( )</code>函数</h4><p>&#96;m</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">  <span class="keyword">var</span> result = arr.<span class="title function_">map</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(index);</span><br><span class="line">    <span class="keyword">return</span> element * element;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result: ===&quot;</span>, result);</span><br></pre></td></tr></table></figure>

<p>在使用<code>map</code>函数的时候一定要注意：在<code>map( )</code>函数的回调函数中需要通过<code>return</code>将处理后的值进行返回，否则会返回<code>undefined</code>.</p>
<p>如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">    <span class="keyword">var</span> result = arr.<span class="title function_">map</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">      <span class="comment">// console.log(index);</span></span><br><span class="line">      element * element;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result: ===&quot;</span>, result);</span><br></pre></td></tr></table></figure>

<p>在上面的计算中，将<code>return</code>关键字省略了，最终返回的结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">[<span class="literal">undefined</span>, <span class="literal">undefined</span>, <span class="literal">undefined</span>, <span class="literal">undefined</span>, <span class="literal">undefined</span>]</span><br></pre></td></tr></table></figure>

<h4 id="使用some-函数与every-函数"><a href="#使用some-函数与every-函数" class="headerlink" title="使用some( )函数与every( )函数"></a>使用<code>some( )</code>函数与<code>every( )</code>函数</h4><p><code>some( )</code>函数与<code>every( )</code>函数的相似之处都是在对数组进行遍历的过程中，判断数组中是否有满足条件的元素，如果有满足条件的就返回<code>true</code>,否则返回<code>false</code>.</p>
<p><code>some()</code>与<code>every()</code>的区别在于:<code>some( )</code>函数只要数组中某个元素满足条件就返回<code>true</code>,不会在对后面的元素进行判断。而<code>every( )</code>函数是数组中每个元素都要满足条件时才会返回<code>true</code>.</p>
<p>例如：要判断数组中是否有大于6的元素的时候，可以通过<code>some( )</code>函数来处理。</p>
<p>而要判断数组中是否所有的元素都大于6，则需要通过<code>every( )</code>函数来处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">element, index, array</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> element &gt; <span class="number">6</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> result = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>].<span class="title function_">some</span>(fn); <span class="comment">//false</span></span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> result = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">7</span>].<span class="title function_">some</span>(fn);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>下面测试一下<code>every( )</code>函数</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">element, index, array</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> element &gt; <span class="number">6</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> result = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">7</span>].<span class="title function_">every</span>(fn); <span class="comment">//false</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>



<p>下面修改一下数组中的元素。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">element, index, array</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> element &gt; <span class="number">6</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> result = [<span class="number">7</span>, <span class="number">8</span>].<span class="title function_">every</span>(fn); <span class="comment">//true</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>现在数组中的元素的值都是大于6，所以返回的结果为<code>true</code>.</p>
<h4 id="使用find-函数"><a href="#使用find-函数" class="headerlink" title="使用find( )函数"></a>使用<code>find( )</code>函数</h4><p><code>find( )</code> 函数用于数组的遍历，当找到第一个满足条件的元素值时，则直接返回该元素值，如果都找不到满足条件的，则返回<code>undefined</code>.</p>
<p><code>find( )</code>方法的参数与<code>forEach</code>是一样的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">  <span class="keyword">const</span> result = arr.<span class="title function_">find</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> element &gt; <span class="number">6</span>;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(result); <span class="comment">// 90                                                                   </span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">  <span class="keyword">const</span> result = arr.<span class="title function_">find</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> element &gt; <span class="number">100</span>; <span class="comment">//undefined</span></span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>以上就是我们比较常用的数组遍历的方式。当然还有我们前面讲解过的<code>filter</code>，<code>reduce</code>函数。</p>
<h3 id="2-6-手动实现find方法"><a href="#2-6-手动实现find方法" class="headerlink" title="2.6 手动实现find方法"></a>2.6 手动实现<code>find</code>方法</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"> &lt;script&gt;</span><br><span class="line">      <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">findTest</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="keyword">var</span> f = <span class="title function_">fn</span>(<span class="variable language_">this</span>[i]);<span class="comment">//把数组元素传递到函数中</span></span><br><span class="line">          <span class="keyword">if</span> (f) &#123; <span class="comment">//如果函数的返回值为true</span></span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>[i]; <span class="comment">//则返回对应的数组元素</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">      <span class="keyword">var</span> result = arr.<span class="title function_">findTest</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> item &gt; <span class="number">6</span>;</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h3 id="2-7-手动实现filter方法"><a href="#2-7-手动实现filter方法" class="headerlink" title="2.7  手动实现filter方法"></a>2.7  手动实现filter方法</h3><p><code>filter</code>函数内部需要一个回调函数，数组中的每个元素都会执行该回调函数，在执行回调函数时会将数组中的每个元素传递给回调函数的参数，在回调函数的函数体内进行判断，如果返回的是<code>true</code>,那么将该元素放到新数组<code>arr</code>中，如果判断的结果为<code>false</code>，则数据不会放到新数组<code>arr</code>中。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//模拟实现filter函数</span></span><br><span class="line">     <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">filterOne</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> newArray = [];</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">         <span class="keyword">var</span> f = <span class="title function_">fn</span>(<span class="variable language_">this</span>[i]);</span><br><span class="line">         <span class="keyword">if</span> (f) &#123;</span><br><span class="line">           newArray.<span class="title function_">push</span>(<span class="variable language_">this</span>[i]);</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> newArray;</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">var</span> array = [<span class="number">65</span>, <span class="number">56</span>, <span class="number">89</span>, <span class="number">53</span>];</span><br><span class="line">     <span class="keyword">var</span> arr = array.<span class="title function_">filterOne</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> item &gt;= <span class="number">60</span>;</span><br><span class="line">     &#125;);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;arr=&quot;</span>, arr);</span><br></pre></td></tr></table></figure>

<h3 id="2-8-手动实现some函数"><a href="#2-8-手动实现some函数" class="headerlink" title="2.8 手动实现some函数"></a>2.8 手动实现some函数</h3><p><code>some()</code> 方法让数组中的每一个元素执行一次回调函数，在该回调函数中执行一些操作，只要有一个操作结果为真，就会返回true。不会在对后面的元素进行判断,否则返回false。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//手动模式some方法</span></span><br><span class="line">   <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">someTest</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">       <span class="keyword">let</span> f = <span class="title function_">fn</span>(<span class="variable language_">this</span>[i]);</span><br><span class="line">       <span class="keyword">if</span> (f) &#123;</span><br><span class="line">         <span class="keyword">return</span> f;</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">let</span> array = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">90</span>];</span><br><span class="line">   <span class="keyword">let</span> result = array.<span class="title function_">someTest</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> item &gt; <span class="number">10</span>;</span><br><span class="line">   &#125;);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result=&quot;</span>, result);</span><br></pre></td></tr></table></figure>

<h3 id="2-9-手动实现every函数"><a href="#2-9-手动实现every函数" class="headerlink" title="2.9  手动实现every函数"></a>2.9  手动实现every函数</h3><p>该方法与<code>some()</code>方法不同，<code>some()</code>方法只要有一个符合条件就返回true,而 <code>every()</code> 方法是数组中所有元素都要符合指定的条件，才会返回true.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//手动模拟实现`every`方法</span></span><br><span class="line">    <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">everyTest</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">      <span class="keyword">let</span> f = <span class="literal">true</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">let</span> f = <span class="title function_">fn</span>(<span class="variable language_">this</span>[i]);</span><br><span class="line">        <span class="keyword">if</span> (!f) &#123;</span><br><span class="line">          <span class="comment">//只要有一个不符合，就立即返回false.</span></span><br><span class="line">          <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> f;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">let</span> array = [<span class="number">11</span>, <span class="number">31</span>, <span class="number">5</span>, <span class="number">71</span>, <span class="number">90</span>];</span><br><span class="line">    <span class="keyword">let</span> result = array.<span class="title function_">everyTest</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> item &gt; <span class="number">10</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result=&quot;</span>, result); <span class="comment">//false</span></span><br></pre></td></tr></table></figure>

<h3 id="2-10-手动实现map方法"><a href="#2-10-手动实现map方法" class="headerlink" title="2.10 手动实现map方法"></a>2.10 手动实现map方法</h3><p><code>map( )</code>函数在对数据进行遍历的时候，会将数组中的每个元素做相应的处理，然后得到新的元素，<strong>并返回一个新的数组</strong>。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//手动实现map方法</span></span><br><span class="line">      <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">mapTest</span> = <span class="keyword">function</span> (<span class="params">fn</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> newArray = [];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="keyword">let</span> f = <span class="title function_">fn</span>(<span class="variable language_">this</span>[i], i, <span class="variable language_">this</span>);</span><br><span class="line">          newArray.<span class="title function_">push</span>(f);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> newArray;</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">90</span>, <span class="number">23</span>];</span><br><span class="line">      <span class="keyword">var</span> result = arr.<span class="title function_">mapTest</span>(<span class="keyword">function</span> (<span class="params">element, index, array</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(index);</span><br><span class="line">        <span class="keyword">return</span> element * element;</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result: ===&quot;</span>, result);</span><br></pre></td></tr></table></figure>

<h3 id="2-11-手动实现reduce方法"><a href="#2-11-手动实现reduce方法" class="headerlink" title="2.11 手动实现reduce方法"></a>2.11 手动实现reduce方法</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">reduceTest</span> = <span class="keyword">function</span> (<span class="params">fn, initialValue</span>) &#123;</span><br><span class="line">       <span class="comment">//如果没有传递initialValue,我们将使用数组的第一项作为initialValue的值</span></span><br><span class="line">       <span class="keyword">let</span> hasInitialValue = initialValue !== <span class="literal">undefined</span>;</span><br><span class="line">       <span class="keyword">let</span> value = hasInitialValue ? initialValue : <span class="variable language_">this</span>[<span class="number">0</span>];</span><br><span class="line">       <span class="comment">//如果没有传递initialValue,则索引从1开始，否则从0开始</span></span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">let</span> i = hasInitialValue ? <span class="number">0</span> : <span class="number">1</span>, len = <span class="variable language_">this</span>.<span class="property">length</span>; i &lt; len; i++) &#123;</span><br><span class="line">         value = <span class="title function_">fn</span>(value, <span class="variable language_">this</span>[i], i, <span class="variable language_">this</span>);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> value;</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">     <span class="keyword">var</span> sum = arr.<span class="title function_">reduceTest</span>(<span class="keyword">function</span> (<span class="params">accumulator, currentValue</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> accumulator + currentValue;</span><br><span class="line">     &#125;, <span class="number">0</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(sum);</span><br></pre></td></tr></table></figure>

<h3 id="2-12-怎样实现数组的去重"><a href="#2-12-怎样实现数组的去重" class="headerlink" title="2.12 怎样实现数组的去重"></a>2.12 怎样实现数组的去重</h3><p>数组去重是指当数组中出现重复的元素的时候，通过一定的方式，将重复的元素去掉。</p>
<h4 id="利用数组遍历去重"><a href="#利用数组遍历去重" class="headerlink" title="利用数组遍历去重"></a>利用数组遍历去重</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 数组去重</span></span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">array</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> newArray = [];</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; array.<span class="property">length</span>; i++) &#123;</span><br><span class="line">         <span class="keyword">if</span> (newArray.<span class="title function_">indexOf</span>(array[i]) === -<span class="number">1</span>) &#123;</span><br><span class="line">           newArray.<span class="title function_">push</span>(array[i]);</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> newArray;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(arr));</span><br></pre></td></tr></table></figure>

<h4 id="利用键值对去重"><a href="#利用键值对去重" class="headerlink" title="利用键值对去重"></a>利用键值对去重</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">array</span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> obj = &#123;&#125;,</span><br><span class="line">       result = [],</span><br><span class="line">       val;</span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; array.<span class="property">length</span>; i++) &#123;</span><br><span class="line">       val = array[i];</span><br><span class="line">       <span class="keyword">if</span> (!obj[val]) &#123;<span class="comment">//根据key获取obj对象中的值</span></span><br><span class="line">         obj[val] = <span class="string">&quot;ok&quot;</span>; <span class="comment">//表示该元素已经出现了</span></span><br><span class="line">         result.<span class="title function_">push</span>(val);</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">return</span> result;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(arr));</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> obj = &#123;&#125;,</span><br><span class="line">    result = [],</span><br><span class="line">    val,</span><br><span class="line">    type;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; array.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    val = array[i];</span><br><span class="line">    type = <span class="keyword">typeof</span> val;</span><br><span class="line">    <span class="keyword">if</span> (!obj[val]) &#123;</span><br><span class="line">      obj[val] = [type];</span><br><span class="line">      result.<span class="title function_">push</span>(val);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (obj[val].<span class="title function_">indexOf</span>(type) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">      obj[val].<span class="title function_">push</span>(type);</span><br><span class="line">      result.<span class="title function_">push</span>(val);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="string">&quot;6&quot;</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(arr));</span><br></pre></td></tr></table></figure>

<h4 id="使用Set数据结构去重"><a href="#使用Set数据结构去重" class="headerlink" title="使用Set数据结构去重"></a>使用<code>Set</code>数据结构去重</h4><p>具体的代码如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="keyword">new</span> <span class="title class_">Set</span>(arr));</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="string">&quot;6&quot;</span>]));</span><br></pre></td></tr></table></figure>



<h3 id="2-13-怎样获取数组中最多的元素"><a href="#2-13-怎样获取数组中最多的元素" class="headerlink" title="2.13 怎样获取数组中最多的元素"></a>2.13 怎样获取数组中最多的元素</h3><h4 id="利用键值对实现"><a href="#利用键值对实现" class="headerlink" title="利用键值对实现"></a>利用键值对实现</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">arr</span>) &#123;</span><br><span class="line">        <span class="comment">//如果数组中没有值，直接返回</span></span><br><span class="line">        <span class="keyword">if</span> (!arr.<span class="property">length</span>) <span class="keyword">return</span>;</span><br><span class="line">        <span class="comment">//如果只有一个值，返回1，表示出现了1次</span></span><br><span class="line">        <span class="keyword">if</span> (arr.<span class="property">length</span> === <span class="number">1</span>) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">var</span> result = &#123;&#125;;</span><br><span class="line">        <span class="comment">//对数组进行遍历</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="keyword">if</span> (!result[arr[i]]) &#123;</span><br><span class="line">            result[arr[i]] = <span class="number">1</span>;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            result[arr[i]]++;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//遍历result对象</span></span><br><span class="line">        <span class="keyword">var</span> keys = <span class="title class_">Object</span>.<span class="title function_">keys</span>(result);</span><br><span class="line">        <span class="keyword">var</span> maxNum = <span class="number">0</span>,</span><br><span class="line">          maxElement;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; keys.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="keyword">if</span> (result[keys[i]] &gt; maxNum) &#123;</span><br><span class="line">            maxNum = result[keys[i]];</span><br><span class="line">            maxElement = keys[i];</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">          <span class="string">&quot;在数组中出现最多的元素是&quot;</span> + maxElement + <span class="string">&quot;,共出现了&quot;</span> + maxNum + <span class="string">&quot;次&quot;</span></span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>];</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(array));</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h4 id="算法优化"><a href="#算法优化" class="headerlink" title="算法优化"></a>算法优化</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">array</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> result = &#123;&#125;;</span><br><span class="line">      <span class="keyword">var</span> maxNum = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">var</span> maxElement = <span class="literal">null</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; array.<span class="property">length</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">var</span> val = array[i];</span><br><span class="line">        result[val] === <span class="literal">undefined</span> ? (result[val] = <span class="number">1</span>) : result[val]++;</span><br><span class="line">        <span class="keyword">if</span> (result[val] &gt; maxNum) &#123;</span><br><span class="line">          maxNum = result[val];</span><br><span class="line">          maxElement = val;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> (</span><br><span class="line">        <span class="string">&quot;在数组中出现最多的元素是&quot;</span> + maxElement + <span class="string">&quot;,共出现了&quot;</span> + maxNum + <span class="string">&quot;次&quot;</span></span><br><span class="line">      );</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>];</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(array));</span><br></pre></td></tr></table></figure>

<h1 id="三、函数"><a href="#三、函数" class="headerlink" title="三、函数"></a>三、函数</h1><h2 id="1、函数定义有哪几种实现方式"><a href="#1、函数定义有哪几种实现方式" class="headerlink" title="1、函数定义有哪几种实现方式"></a>1、函数定义有哪几种实现方式</h2><p>在使用函数前，先需要对函数进行定义。关于函数的定义总体上可以分为三类。</p>
<p>第一类是函数声明。</p>
<p>第二类是函数表达式</p>
<p>第三类是通过<code>Function</code>构造函数来完成函数的定义。</p>
<p>首先来看一下<strong>函数的声明</strong>。</p>
<p>函数声明是直接通过<code>function</code>关键字接一个函数名，同时可以接收参数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">num1, num2</span>)&#123;</span><br><span class="line">     <span class="keyword">return</span> num1 + num2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>函数表达式</strong></p>
<p>函数表达式的形式类似于普通变量的初始化，只不过这个变量初始化的值是一个函数。如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> sum =  <span class="keyword">function</span> (<span class="params">num1,num2</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> num1 + num2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个函数表达式没有名称，属于匿名函数表达式。</p>
<p><strong><code>Function( )</code>构造函数</strong></p>
<p>使用<code>new</code>操作符，调用<code>Function( )</code>构造函数，传入参数，也可以定义一个函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> sum = <span class="keyword">new</span> <span class="title class_">Function</span>(<span class="string">&#x27;num1&#x27;</span>,<span class="string">&#x27;num2&#x27;</span>, <span class="string">&#x27;return a+b &#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>其中的参数，除了最后一个参数是要执行的函数体，其它的参数都是函数的形参。</p>
<h2 id="2、Function-构造函数定义函数的问题"><a href="#2、Function-构造函数定义函数的问题" class="headerlink" title="2、Function( )构造函数定义函数的问题"></a>2、Function( )构造函数定义函数的问题</h2><p>但是，我们在实际的应用中很少使用<code>Function( )</code>构造函数来实现对函数的定义。</p>
<p>原因是：</p>
<p>第一：<code>Function( )</code> 构造函数每次执行时，都会解析函数体，并创建一个新的函数对象，所以当在一个循环或者是一个频繁执行的函数中去使用<code>Function( )</code>构造函数的时候，相对来说性能是比较低的。</p>
<p>第二：通过<code>Function( )</code> 构造函数创建的函数，并不遵循典型的作用域。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="string">&quot;12&quot;</span>;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">fun</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> a = <span class="string">&quot;11&quot;</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Function</span>(<span class="string">&quot;return a&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fun</span>()());</span><br></pre></td></tr></table></figure>

<h2 id="3、函数表达式的应用场景"><a href="#3、函数表达式的应用场景" class="headerlink" title="3、函数表达式的应用场景"></a>3、函数表达式的应用场景</h2><p>关于函数表达式非常典型的应用就是实现了块级作用域</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> _name = <span class="string">&quot;&quot;</span>;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">getName</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> _name;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">setName</span>: <span class="keyword">function</span> (<span class="params">userName</span>) &#123;</span><br><span class="line">          _name = userName;</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;)();</span><br><span class="line">    person.<span class="title function_">setName</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="title function_">getName</span>());</span><br></pre></td></tr></table></figure>



<h2 id="4、函数声明与函数表达式有什么区别"><a href="#4、函数声明与函数表达式有什么区别" class="headerlink" title="4、函数声明与函数表达式有什么区别"></a>4、函数声明与函数表达式有什么区别</h2><p>函数声明与函数表达式虽然是两种定义函数的方式，但是两者之间还是有区别的。</p>
<p>第一点就是：函数名称</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 函数声明，函数名称sum是必须的</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span> (num1,num2)&#123;</span><br><span class="line">	<span class="keyword">return</span> num1 + num2 </span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 没有函数名称的匿名函数表达式</span></span><br><span class="line"><span class="keyword">var</span> sum = <span class="keyword">function</span> (<span class="params">num1,num2</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> num1 + num2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第二点就是关于：函数提升</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">add</span>(<span class="number">1</span>, <span class="number">2</span>)); <span class="comment">// 3</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">sum</span>(<span class="number">3</span>, <span class="number">6</span>)); <span class="comment">// Uncaught TypeError: sum is not a function</span></span><br><span class="line"><span class="comment">// 函数声明</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> num1 + num2;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 函数表达式</span></span><br><span class="line"><span class="keyword">var</span> sum = <span class="keyword">function</span> (<span class="params">num1, num2</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> num1 + num2;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>



<h2 id="5、函数常见的调用模式有哪些"><a href="#5、函数常见的调用模式有哪些" class="headerlink" title="5、函数常见的调用模式有哪些"></a>5、函数常见的调用模式有哪些</h2><p><strong>函数调用模式</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"> <span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> num1 + num2;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="comment">// 函数表达式</span></span><br><span class="line">     <span class="keyword">var</span> sum = <span class="keyword">function</span> (<span class="params">num1, num2</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> num1 + num2;</span><br><span class="line">     &#125;;</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">add</span>(<span class="number">1</span>, <span class="number">2</span>)); </span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">sum</span>(<span class="number">3</span>, <span class="number">6</span>));</span><br></pre></td></tr></table></figure>

<p><strong>方法调用模式</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">   <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">   <span class="attr">getUserName</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">   &#125;,</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">getUserName</span>());</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">       <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">       <span class="attr">getUserName</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="comment">// console.log(obj.getUserName());</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(obj[<span class="string">&quot;getUserName&quot;</span>]());</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">     <span class="attr">getUserName</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">     <span class="attr">setUserName</span>: <span class="keyword">function</span> (<span class="params">name</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = name;</span><br><span class="line">       <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">setUserName</span>(<span class="string">&quot;lisi&quot;</span>).<span class="title function_">getUserName</span>());<span class="comment">// lisi</span></span><br></pre></td></tr></table></figure>

<p><strong>构造器(构造函数)调用模式</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//定义构造函数</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">userName</span> = name; <span class="comment">//定义属性</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 在原型上定义函数</span></span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getUserName</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="comment">// 通过new来创建实例</span></span><br><span class="line">    <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">    <span class="comment">// 调用原型上的方法</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">getUserName</span>());</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> num1 + num2;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">//定义一个对象</span></span><br><span class="line">   <span class="keyword">var</span> obj = &#123;&#125;;</span><br><span class="line">   <span class="comment">//通过call()和apply( )函数调用sum( )函数</span></span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(sum.<span class="title function_">call</span>(obj, <span class="number">2</span>, <span class="number">6</span>));</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(sum.<span class="title function_">apply</span>(obj, [<span class="number">3</span>, <span class="number">6</span>]));</span><br></pre></td></tr></table></figure>



<p><strong>匿名函数调用模式</strong></p>
<p>所谓的匿名函数，就是没有函数名称的函数。匿名函数的调用有两种方式，一种是通过函数表达式定义函数，并赋值给变量，通过变量进行调用。如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过函数表达式定义匿名函数，并赋值给变量sum</span></span><br><span class="line"><span class="keyword">var</span> sum =funciton (num1,num2)&#123;</span><br><span class="line">    <span class="keyword">return</span> num1 + num2</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 通过sum来进行调用</span></span><br><span class="line"><span class="title function_">sum</span>(<span class="number">2</span>,<span class="number">6</span>)</span><br></pre></td></tr></table></figure>

<p>另外一种是使用小括号<code>()</code>将匿名函数括起来，然后在后面使用小括号<code>( )</code>,传递对应的参数从而完成对应的调用。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">(<span class="keyword">function</span> (<span class="params">num1, num2</span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 + num2);</span><br><span class="line">     &#125;)(<span class="number">2</span>, <span class="number">6</span>);</span><br></pre></td></tr></table></figure>



<h2 id="6、实参与形参有哪些区别"><a href="#6、实参与形参有哪些区别" class="headerlink" title="6、实参与形参有哪些区别"></a>6、实参与形参有哪些区别</h2><p>第一：在函数的调用过程中，数据传递是单向的，也就是只能把实参的值传递给形参，而不能把形参的值反向传递给实参</p>
<p>第二：当实参是基本数据类型的值的时候，在向形参传递的时候，实际上是将实参的值复制一份传递给形参，在函数运行结束以后</p>
<p>形参释放，而实参中的值不会发生变化。当实参是引用类型的值的时候，实际是将实参的内存地址传递给形参，即实参与形参都指向了</p>
<p>相同的内存地址，此时形参可以修改实参的值。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123; <span class="attr">age</span>: <span class="number">21</span> &#125;;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">       obj.<span class="property">age</span> = <span class="number">22</span>;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>(person);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">age</span>);</span><br></pre></td></tr></table></figure>

<p>第三：函数可以不用定义形参，在函数体中可以通过<code>arguments</code>对象获取传递过来的实参的值，并进行处理。</p>
<p>第四：在函数定义形参时，形参的个数并一定要和实参的个数相同，实参与形参会按照从前向后的顺序进行匹配，没有匹配到的形参被当作<code>undefined</code>来处理。</p>
<p>第五：实参并不需要与形参的数据类型一致，因为形参的数据类型只能在执行的时候才能够被确定，因为会通过隐式数据类型的转换。</p>
<h2 id="7、介绍一下arguments对象"><a href="#7、介绍一下arguments对象" class="headerlink" title="7、介绍一下arguments对象"></a>7、介绍一下arguments对象</h2><p><code>arguments</code>对象是所有函数都具有的一个内置的局部变量，表示的是函数实际接收到的参数，是一个类似数组的结构。</p>
<p>下面我们说一下<code>arguments</code>对象都具有哪些性质。</p>
<p>第一：<code>arguments</code>对象只能在函数内部使用，无法在函数的外部访问到<code>arguments</code>对象。同时<code>arguments</code>对象存在于函数级的作用域中。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>); <span class="comment">//Uncaught ReferenceError: arguments is not defined</span></span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>.<span class="property">length</span>);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>

<p>第二：可以通过索引来访问<code>arguments</code>对象中的内容，因为<code>arguments</code>对象类似数组结构。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">0</span>]); <span class="comment">// 1</span></span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">1</span>]); <span class="comment">// 2</span></span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">2</span>]); <span class="comment">// undefined</span></span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>

<p>第三：<code>arguments</code> 对象的值由实参决定，不是由形参决定。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>.<span class="property">length</span>); <span class="comment">// 2</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>

<p>因为<code>arguments</code>对象的<code>length</code>属性是由实际传递的实参的个数决定的，所以这里输出的是2.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">    <span class="variable language_">arguments</span>[<span class="number">0</span>] = <span class="number">23</span>;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;num1=&quot;</span>, num1); <span class="comment">//23</span></span><br><span class="line">    num2 = <span class="number">33</span>;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">1</span>]); <span class="comment">// 33</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">  <span class="comment">// arguments[0] = 23;</span></span><br><span class="line">  <span class="comment">// console.log(&quot;num1=&quot;, num1); //23</span></span><br><span class="line">  <span class="comment">// num2 = 33;</span></span><br><span class="line">  <span class="comment">// console.log(arguments[1]); // 33</span></span><br><span class="line"></span><br><span class="line">  <span class="variable language_">arguments</span>[<span class="number">2</span>] = <span class="number">19</span>;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(num3); <span class="comment">//undefined</span></span><br><span class="line">  num3 = <span class="number">10</span>;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">2</span>]); <span class="comment">// 19</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">       <span class="comment">// arguments[0] = 23;</span></span><br><span class="line">       <span class="comment">// console.log(&quot;num1=&quot;, num1); //23</span></span><br><span class="line">       <span class="comment">// num2 = 33;</span></span><br><span class="line">       <span class="comment">// console.log(arguments[1]); // 33</span></span><br><span class="line"></span><br><span class="line">       <span class="variable language_">arguments</span>[<span class="number">2</span>] = <span class="number">19</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(num3); <span class="comment">//undefined</span></span><br><span class="line">       num3 = <span class="number">10</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>[<span class="number">2</span>]); <span class="comment">// 19</span></span><br><span class="line"></span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">arguments</span>.<span class="property">length</span>); <span class="comment">// 2 长度还是2</span></span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>



<h2 id="8、arguments对象有哪些应用场景"><a href="#8、arguments对象有哪些应用场景" class="headerlink" title="8、arguments对象有哪些应用场景"></a>8、arguments对象有哪些应用场景</h2><p>第一：进行参数个数的判断。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">      <span class="comment">// 判断传递的参数个数是否正确</span></span><br><span class="line">      <span class="keyword">if</span> (<span class="variable language_">arguments</span>.<span class="property">length</span> !== <span class="number">3</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(</span><br><span class="line">          <span class="string">&quot;希望传递3个参数，实际传递的参数个数为:&quot;</span> + <span class="variable language_">arguments</span>.<span class="property">length</span></span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>

<p>第二：对任意个数参数的处理，也就是说只会对函数中前几个参数做特定处理，后面的参数不论传递多少个都会统一进行处理，这种情况我们可以使用<code>arguments</code>对象来完成。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">sep</span>) &#123;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">var</span> arr = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>, <span class="number">1</span>);</span><br><span class="line">      <span class="comment">// console.log(arr); // [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]</span></span><br><span class="line">      <span class="keyword">return</span> arr.<span class="title function_">join</span>(sep);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="string">&quot;-&quot;</span>, <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>));</span><br></pre></td></tr></table></figure>



<p>第三：模拟函数的重载</p>
<p>什么是函数的重载呢？</p>
<p>函数的重载指的是在函数名称相同的情况下，函数的形参的类型不同或者是个数不同。</p>
<p>但是在<code>JavaScript</code>中没有函数的重载。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> num1 + num2;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">num1, num2, num3</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> num1 + num2 + num3;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>)); <span class="comment">// NaN</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)); <span class="comment">// 6</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="comment">//将arguments对象转换成数组</span></span><br><span class="line">     <span class="keyword">var</span> arr = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>);</span><br><span class="line">     <span class="comment">// console.log(arr);  // [1,2]</span></span><br><span class="line">    <span class="comment">//调用数组中的reduce方法完成数据的计算</span></span><br><span class="line">     <span class="keyword">return</span> arr.<span class="title function_">reduce</span>(<span class="keyword">function</span> (<span class="params">pre, currentValue</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> pre + currentValue;</span><br><span class="line">     &#125;);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>));</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>));</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>));</span><br></pre></td></tr></table></figure>

<h2 id="9、说一下普通函数与构造函数的区别"><a href="#9、说一下普通函数与构造函数的区别" class="headerlink" title="9、说一下普通函数与构造函数的区别"></a>9、说一下普通函数与构造函数的区别</h2><p>在<code>JavaScript</code>的函数中，有一类比较特殊的函数：’构造函数’。当我们创建对象的时候，经常会使用构造函数。</p>
<p>构造函数与普通函数的区别：</p>
<p>第一：构造函数的函数名的第一字母通常会大写。</p>
<p>第二：在构造函数的函数体内可以使用<code>this</code>关键字，表示创生成的对象实例。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person);</span><br></pre></td></tr></table></figure>



<p>第三：在使用构造函数的时候，必须与<code>new</code>操作符配合使用。</p>
<p>第四：构造函数的执行过程与普通函数也是不一样的。</p>
<p>代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">   <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">   <span class="variable language_">this</span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">username</span>);</span><br><span class="line">   &#125;;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line"> <span class="keyword">var</span> p2 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;lisi&quot;</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">sayHi</span> === p2.<span class="property">sayHi</span>); <span class="comment">// false</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">    <span class="comment">// this.sayHi = function () &#123;</span></span><br><span class="line">    <span class="comment">//   console.log(this.username);</span></span><br><span class="line">    <span class="comment">// &#125;;</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">username</span>);</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">  <span class="keyword">var</span> p2 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;lisi&quot;</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">sayHi</span> === p2.<span class="property">sayHi</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>



<h2 id="10、什么是变量提升，什么是函数提升"><a href="#10、什么是变量提升，什么是函数提升" class="headerlink" title="10、什么是变量提升，什么是函数提升"></a>10、什么是变量提升，什么是函数提升</h2><p>在<code>javascript</code>中存在一些比较奇怪的现象。在一个函数体内，变量在定义之前就可以被访问到，而不会抛出异常。</p>
<p>如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(num); <span class="comment">// undefined</span></span><br><span class="line">   <span class="keyword">var</span> num = <span class="number">2</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="title function_">fn</span>();</span><br></pre></td></tr></table></figure>

<p>同样函数在定义之前也可以被调用，而不会抛出异常。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">fn</span>();</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>导致出现以上情况的原因是，在<code>javascript</code>中存在变量提升与函数提升的机制。</p>
<p>在讲解变量提升之前，先来说以作用域的问题。</p>
<h3 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h3><p>在<code>JavaScript</code>中，一个变量的定义与调用都是在一个固定的范围内的，这个范围我们称之为作用域。</p>
<p>作用域可以分为全局的作用域，局部作用域(函数作用域)和块级作用域。</p>
<p>如下程序：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> userName = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(userName);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>(); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>



<p>下面，再看如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userName = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(userName);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">fn</span>(); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>



<p>综上两个案例，我们可以总结出，<strong>作用域本质就是一套规则，用于确定在何处以及如何查找变量的规则。</strong></p>
<p>下面，我们再来看一个比较复杂的结构图，来体验一下作用域</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E4%BD%9C%E7%94%A8%E5%9F%9F.png"></p>
<ul>
<li>作用域链</li>
</ul>
<p>下面，我们再来看一下前面的代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userName = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(userName);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">fn</span>(); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>

<p>我们在查找<code>userName</code>这个变量的时候，现在函数的作用域中进行查找，没有找到，再去全局作用域中查找。你会注意到，这是一个往外层查找的过程，即顺着一条链条从下往上查找变量。这个链条，我们就称之为作用域链。</p>
<p>如下图所示：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE.png"></p>
<p>对应的代码如下：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE2.png"></p>
<h3 id="面试中关于作用域与作用域链的问题"><a href="#面试中关于作用域与作用域链的问题" class="headerlink" title="面试中关于作用域与作用域链的问题"></a>面试中关于作用域与作用域链的问题</h3><p>  第一题：以下代码的执行结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">fn1</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">fn2</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">fn3</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> a = <span class="number">4</span>;</span><br><span class="line">       <span class="title function_">fn2</span>();</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> a = <span class="number">2</span>;</span><br><span class="line">     <span class="keyword">return</span> fn3;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> fn = <span class="title function_">fn1</span>();</span><br><span class="line">   <span class="title function_">fn</span>(); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>



<p>第二题：以下代码的执行结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">fn1</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fn3</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> a = <span class="number">4</span>;</span><br><span class="line">      <span class="title function_">fn2</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> a = <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">return</span> fn3;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">fn2</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> fn = <span class="title function_">fn1</span>();</span><br><span class="line">  <span class="title function_">fn</span>(); <span class="comment">// 1</span></span><br></pre></td></tr></table></figure>



<p>第三题：以下代码的输出结果为</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fn1</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">fn3</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">fn2</span>(<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> a;</span><br><span class="line">        <span class="title function_">fn2</span>();</span><br><span class="line">        a = <span class="number">4</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> a = <span class="number">2</span>;</span><br><span class="line">      <span class="keyword">return</span> fn3;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> fn = <span class="title function_">fn1</span>();</span><br><span class="line">    <span class="title function_">fn</span>(); <span class="comment">//undefined</span></span><br></pre></td></tr></table></figure>



<p>第四题：以下代码的输出结果为：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> x = <span class="number">10</span>;</span><br><span class="line">     <span class="title function_">bar</span>(); <span class="comment">//10</span></span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(x);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> x = <span class="number">30</span>;</span><br><span class="line">       <span class="title function_">foo</span>();</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure>



<p>第五题： 以下代码的输出结果为：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> x = <span class="number">10</span>;</span><br><span class="line">    <span class="title function_">bar</span>(); <span class="comment">//30</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> x = <span class="number">30</span>;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(x);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">foo</span>();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<p>第六题：以下代码的输出结果为:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> x = <span class="number">10</span>;</span><br><span class="line">   <span class="title function_">bar</span>(); <span class="comment">//30</span></span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> x = <span class="number">30</span>;</span><br><span class="line">     (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(x);</span><br><span class="line">     &#125;)();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>



<h3 id="变量提升"><a href="#变量提升" class="headerlink" title="变量提升"></a>变量提升</h3><p>所谓变量提升，是将变量的声明提升到函数顶部的位置，也就是将变量声明提升到变量所在的作用域的顶端，而变量的赋值并不会被提升。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> str = <span class="string">&quot;hello world&quot;</span>;</span><br><span class="line">    (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(str);</span><br><span class="line">      <span class="keyword">var</span> str = <span class="string">&quot;hello vue&quot;</span>;</span><br><span class="line">    &#125;)(); <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> str = <span class="string">&quot;hello world&quot;</span>;</span><br><span class="line">(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> str; <span class="comment">//变量的声明得到提升</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(str);</span><br><span class="line">  str = <span class="string">&quot;hello vue&quot;</span>; <span class="comment">// 变量的赋值没有得到提升</span></span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure>



<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(str);</span><br><span class="line">    str = <span class="string">&quot;hello vue&quot;</span>;</span><br><span class="line">  &#125;)(); <span class="comment">// str is not defined</span></span><br></pre></td></tr></table></figure>



<p>以下代码的执行结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a); <span class="comment">//1</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(b); <span class="comment">//undefined</span></span><br><span class="line">      <span class="keyword">var</span> b = <span class="number">2</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">foo</span>();</span><br></pre></td></tr></table></figure>

<p>上面的代码等价于</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> a;</span><br><span class="line">  <span class="keyword">var</span> b;</span><br><span class="line">  a = <span class="number">1</span>;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(a); <span class="comment">// 1</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(b); <span class="comment">// undefined</span></span><br><span class="line">  b = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">foo</span>();</span><br></pre></td></tr></table></figure>

<h3 id="函数提升"><a href="#函数提升" class="headerlink" title="函数提升"></a>函数提升</h3><p>不仅通过<code>var</code>定义的变量会出现提升的情况，使用函数声明方式定义的函数也会出现提升。</p>
<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">foo</span>(); <span class="comment">// 函数提升</span></span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">foo</span>() <span class="comment">//&#x27;hello&#x27;</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">foo</span>(); <span class="comment">// foo is not a function</span></span><br><span class="line">   <span class="keyword">var</span> foo = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">   &#125;;</span><br></pre></td></tr></table></figure>

<p>看一下如下程序的执行结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="title function_">bar</span>();</span><br><span class="line">       <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="number">9</span>;</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">foo</span>()); <span class="comment">// 9</span></span><br></pre></td></tr></table></figure>



<p>如下程序的执行结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="literal">true</span>;</span><br><span class="line">    <span class="title function_">foo</span>();</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (a) &#123;</span><br><span class="line">        <span class="keyword">var</span> a = <span class="number">20</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a); <span class="comment">// undefined</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<p>以上的代码的执行过程如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a;</span><br><span class="line">a = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="keyword">var</span> a;</span><br><span class="line">    <span class="keyword">if</span>(a)&#123;</span><br><span class="line">        a=<span class="number">20</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(a)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">foo</span>()</span><br></pre></td></tr></table></figure>



<p>如下程序的执行结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">v</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">a</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="title function_">v</span>(); <span class="comment">// 1</span></span><br></pre></td></tr></table></figure>



<p>下面我们再来看一段代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> foo); <span class="comment">// function</span></span><br><span class="line">       <span class="keyword">var</span> foo = <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">       <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="string">&quot;abc&quot;</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> foo); <span class="comment">// string</span></span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">fn</span>();</span><br></pre></td></tr></table></figure>

<p>执行上面的代码，首先打印的是<code>function</code>,然后是<code>string</code>.</p>
<p>上面的代码实际上可以修改成如下的代码段。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// 变量提升到函数的顶部</span></span><br><span class="line">        <span class="keyword">var</span> foo;</span><br><span class="line">        <span class="comment">// 函数提升，但是优先级低，所以出现在变量声明的后面。</span></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> <span class="string">&quot;abc&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> foo); <span class="comment">//function</span></span><br><span class="line">        foo = <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> foo); <span class="comment">//string</span></span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>下面，我们再来看一段代码，看一下对应的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line">       <span class="keyword">function</span> <span class="title function_">b</span>(<span class="params"></span>) &#123;</span><br><span class="line">         a = <span class="number">10</span>;</span><br><span class="line">         <span class="keyword">return</span>;</span><br><span class="line">         <span class="keyword">function</span> <span class="title function_">a</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="title function_">b</span>();</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">foo</span>(); <span class="comment">//1</span></span><br></pre></td></tr></table></figure>

<p>上面的代码可以修改成如下的代码。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">//变量a提升</span></span><br><span class="line">       <span class="keyword">var</span> a;</span><br><span class="line">    <span class="comment">//函数声明b的提升</span></span><br><span class="line">       <span class="keyword">function</span> <span class="title function_">b</span>(<span class="params"></span>) &#123;</span><br><span class="line">           <span class="comment">//内部的函数声明a的提升</span></span><br><span class="line">         <span class="keyword">function</span> <span class="title function_">a</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">           <span class="comment">//全局变量</span></span><br><span class="line">         a = <span class="number">10</span>;</span><br><span class="line">         <span class="keyword">return</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       a = <span class="number">1</span>;</span><br><span class="line">       <span class="title function_">b</span>();</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(a);<span class="comment">//在当前的作用域中，可以找到变量a，不需要获取全局变量a,所以其值为1，所以打印结果为1，</span></span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">foo</span>();</span><br></pre></td></tr></table></figure>



<h2 id="11、闭包"><a href="#11、闭包" class="headerlink" title="11、闭包"></a>11、闭包</h2><p>在正常的情况下，如果定义了一个函数，就会产生一个函数作用域，在函数体中的局部变量会在这个函数的作用域中使用。</p>
<p>一旦函数执行完毕后，函数所占用的空间就会被回收，存在于函数体中的局部变量同样也会被回收，回收后将不能被访问。</p>
<p>如果我们期望在函数执行完毕以后，函数中的局部变量仍然可以被访问到，应该怎样实现呢？</p>
<p>这里我们可以通过闭包来实现。</p>
<p>在讲解闭包的问题之前，我们先说一个概念，执行上下文环境。</p>
<h3 id="执行上下文环境"><a href="#执行上下文环境" class="headerlink" title="执行上下文环境"></a>执行上下文环境</h3><p><code>JavaScript</code>的每段代码的执行都会存在于一个执行上下文环境中。</p>
<p>执行上下文有且只有三类，全局执行上下文，函数上下文，与<code>eval</code>上下文；由于<code>eval</code>一般不会使用，这里不做讨论</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">f1</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">f2</span>();</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">f2</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">f3</span>();</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">f3</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title function_">f1</span>();<span class="comment">//3 2 1</span></span><br></pre></td></tr></table></figure>

<p>为了方便理解，我们假设执行栈是一个数组，在代码执行初期一定会创建全局执行上下文并压入栈，因此过程大致如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//代码执行前创建全局执行上下文</span></span><br><span class="line"><span class="title class_">ECStack</span> = [globalContext];</span><br><span class="line"><span class="comment">// f1调用</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">push</span>(<span class="string">&#x27;f1 functionContext&#x27;</span>);</span><br><span class="line"><span class="comment">// f1又调用了f2，f2执行完毕之前无法console 1</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">push</span>(<span class="string">&#x27;f2 functionContext&#x27;</span>);</span><br><span class="line"><span class="comment">// f2又调用了f3，f3执行完毕之前无法console 2</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">push</span>(<span class="string">&#x27;f3 functionContext&#x27;</span>);</span><br><span class="line"><span class="comment">// f3执行完毕，输出3并出栈</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">pop</span>();</span><br><span class="line"><span class="comment">// f2执行完毕，输出2并出栈</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">pop</span>();</span><br><span class="line"><span class="comment">// f1执行完毕，输出1并出栈</span></span><br><span class="line"><span class="title class_">ECStack</span>.<span class="title function_">pop</span>();</span><br><span class="line"><span class="comment">// 此时执行栈中只剩下一个全局执行上下文</span></span><br></pre></td></tr></table></figure>



<h3 id="什么是闭包"><a href="#什么是闭包" class="headerlink" title="什么是闭包"></a>什么是闭包</h3><p>关于闭包的官方概念：一个拥有许多变量和绑定了这些变量执行上下文环境的表达式，通常是一个函数。</p>
<p>简单的理解就是：闭包就是能够读取其它函数内部变量的函数。由于在<code>JavaScript</code>语言中，只有函数内部的子函数才能读取局部变量，因此可以把闭包简单理解成“定义在一个函数内部的函数”。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">outer</span> () &#123;</span><br><span class="line">    ...</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">inner</span> () &#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>所以，本质上，闭包就是将函数内部和函数外部连接起来的一座桥梁。</p>
<p>闭包有两个比较显著的特点：</p>
<p>第一：函数拥有的外部变量的引用，在函数返回时，该变量仍然处于活跃状态。</p>
<p>第二：闭包作为一个函数返回时，其执行上下文环境不会销毁，仍然处于执行上下文环境中。</p>
<p>在<code>JavaScript</code>中存在一种内部函数，即函数声明和函数表达式可以位于另一个函数的函数体内，在内部函数中可以访问外部函数声明的变量，当这个内部函数在包含它们外部函数之外被调用时，就会形成闭包。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">makeFunc</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> name = <span class="string">&quot;Mozilla&quot;</span>;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">displayName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="title function_">alert</span>(name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> displayName;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> myFunc = <span class="title function_">makeFunc</span>();</span><br><span class="line"><span class="title function_">myFunc</span>();</span><br></pre></td></tr></table></figure>

<p>下面，我们再来看另外一段代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> max = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params">x</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (x &gt; max) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(x);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> f1 = <span class="title function_">fn</span>();</span><br><span class="line">  <span class="title function_">f1</span>(<span class="number">11</span>); <span class="comment">// 11</span></span><br></pre></td></tr></table></figure>



<h3 id="闭包的应用场景"><a href="#闭包的应用场景" class="headerlink" title="闭包的应用场景"></a>闭包的应用场景</h3><p> <strong>应用缓存</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> cacheApp = (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> cache = &#123;&#125;;</span><br><span class="line">     <span class="keyword">return</span> &#123;</span><br><span class="line">       <span class="attr">getResult</span>: <span class="keyword">function</span> (<span class="params">id</span>) &#123;</span><br><span class="line">         <span class="comment">// 如果在内存中，则直接返回</span></span><br><span class="line">         <span class="keyword">if</span> (id <span class="keyword">in</span> cache) &#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="string">&quot;得到的结果为:&quot;</span> + cache[id];</span><br><span class="line">         &#125;</span><br><span class="line">         <span class="comment">//经过耗时函数的处理</span></span><br><span class="line">         <span class="keyword">var</span> result = <span class="title function_">timeFn</span>(id);</span><br><span class="line">         <span class="comment">//更新缓存</span></span><br><span class="line">         cache[id] = result;</span><br><span class="line">         <span class="comment">//返回计算的结果</span></span><br><span class="line">         <span class="keyword">return</span> <span class="string">&quot;得到的结果为:&quot;</span> + result;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">   &#125;)();</span><br><span class="line">   <span class="comment">//耗时函数</span></span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">timeFn</span>(<span class="params">id</span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;这是一个非常耗时的任务&quot;</span>);</span><br><span class="line">     <span class="keyword">return</span> id;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(cacheApp.<span class="title function_">getResult</span>(<span class="number">23</span>));</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(cacheApp.<span class="title function_">getResult</span>(<span class="number">23</span>));</span><br></pre></td></tr></table></figure>



<p><strong>代码封装</strong></p>
<p>在编程的时候，我们提倡将一定特征的代码封装到一起，只需要对外暴露对应的方法就可以，从而不用关心内部逻辑的实现。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">var</span> stack = (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="comment">//使用数组模拟栈</span></span><br><span class="line">       <span class="keyword">var</span> arr = [];</span><br><span class="line">       <span class="keyword">return</span> &#123;</span><br><span class="line">         <span class="attr">push</span>: <span class="keyword">function</span> (<span class="params">value</span>) &#123;</span><br><span class="line">           arr.<span class="title function_">push</span>(value);</span><br><span class="line">         &#125;,</span><br><span class="line">         <span class="attr">pop</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">           <span class="keyword">return</span> arr.<span class="title function_">pop</span>();</span><br><span class="line">         &#125;,</span><br><span class="line">         <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">           <span class="keyword">return</span> arr.<span class="property">length</span>;</span><br><span class="line">         &#125;,</span><br><span class="line">       &#125;;</span><br><span class="line">     &#125;)();</span><br><span class="line">     stack.<span class="title function_">push</span>(<span class="string">&quot;abc&quot;</span>);</span><br><span class="line">     stack.<span class="title function_">push</span>(<span class="string">&quot;def&quot;</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stack.<span class="title function_">size</span>()); <span class="comment">// 2</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(stack.<span class="title function_">pop</span>()); <span class="comment">// def</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(stack.<span class="title function_">size</span>()); <span class="comment">// 1</span></span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>



<h3 id="闭包常见面试题"><a href="#闭包常见面试题" class="headerlink" title="闭包常见面试题"></a>闭包常见面试题</h3><p>第一：如下程序执行的结果为：</p>
<p>获取所单击的<code>li</code>元素的索引值</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span>a<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span>b<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span>c<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span>d<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span>e<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>对应的<code>js</code>代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 获取所单击的`li`元素的索引值</span></span><br><span class="line">    <span class="keyword">var</span> list = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;ul&quot;</span>)[<span class="number">0</span>].<span class="property">children</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; list.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      list[i].<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(i);</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<p>可以采用闭包解决这个问题：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> list = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;ul&quot;</span>)[<span class="number">0</span>].<span class="property">children</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; list.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      (<span class="keyword">function</span> (<span class="params">index</span>) &#123;</span><br><span class="line">        list[index].<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(index);</span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;)(i);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<p>第二：如下程序输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(arr[i]);</span><br><span class="line">      &#125;, <span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<p>代码修改后的内容为：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">var</span> arr = [<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">  (<span class="keyword">function</span> (<span class="params">index</span>) &#123;</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(arr[index]);</span><br><span class="line">    &#125;, <span class="number">1000</span>);</span><br><span class="line">  &#125;)(i);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>第三：以下程序打印结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userName = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line"><span class="keyword">var</span> person = &#123;</span><br><span class="line">  <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>,</span><br><span class="line">  <span class="attr">method</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="title function_">method</span>()()); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userName = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">    <span class="keyword">var</span> person = &#123;</span><br><span class="line">      <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>,</span><br><span class="line">      <span class="attr">method</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> that = <span class="variable language_">this</span>; <span class="comment">//用that保存person的this</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> that.<span class="property">userName</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="title function_">method</span>()());</span><br></pre></td></tr></table></figure>



<p>第四：以下程序的输出结果</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">create</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> a = <span class="number">100</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> fn = <span class="title function_">create</span>();</span><br><span class="line">  <span class="keyword">var</span> a = <span class="number">200</span>;</span><br><span class="line">  <span class="title function_">fn</span>(); <span class="comment">// 100</span></span><br></pre></td></tr></table></figure>



<p>第五：以下程序的输出结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">print</span>(<span class="params">fn</span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> a = <span class="number">200</span>;</span><br><span class="line">     <span class="title function_">fn</span>();</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> a = <span class="number">100</span>;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(a); <span class="comment">// 100</span></span><br><span class="line">   &#125;</span><br><span class="line">   <span class="title function_">print</span>(fn);</span><br></pre></td></tr></table></figure>



<h3 id="闭包优缺点"><a href="#闭包优缺点" class="headerlink" title="闭包优缺点"></a>闭包优缺点</h3><p>闭包的优点：</p>
<p>第一：保护函数内变量的安全，实现封装，防止变量流入其它环境发生命名冲突，造成环境污染。</p>
<p>第二：在适当的时候，可以在内存中维护变量并缓存，提高执行效率</p>
<p>闭包的缺点：</p>
<p>消耗内存：通常来说，函数的活动对象会随着执行上下文环境一起被销毁，但是由于闭包引用的是外部函数的活动对象，因此这个活动对象无法被销毁，所以说，闭包比一般的函数需要消耗更多的内存。</p>
<h2 id="12、this指向"><a href="#12、this指向" class="headerlink" title="12、this指向"></a>12、this指向</h2><h3 id="常见面试题"><a href="#常见面试题" class="headerlink" title="常见面试题"></a>常见面试题</h3><p>我们知道，当我们创建一个构造函数的实例的时候，需要通过<code>new</code>操作符来完成创建，当创建完成后，函数体中的<code>this</code>指向了这个实例。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">userName</span>);</span><br></pre></td></tr></table></figure>

<p>如果，我们将上面的<code>Person</code>函数当作一个普通函数来调用执行，那么对应的<code>this</code>会指向谁呢？</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Person</span>(<span class="string">&quot;lisi&quot;</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">window</span>.<span class="property">userName</span>);</span><br></pre></td></tr></table></figure>

<p>通过上面的程序，我们可以总结出，<code>this</code>指向的永远是函数的调用者。</p>
<p>第一：如下程序的输出结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">10</span>;</span><br><span class="line">  <span class="keyword">var</span> obj = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">120</span>,</span><br><span class="line">    <span class="attr">method</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> bar = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">a</span>); <span class="comment">// 10</span></span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="title function_">bar</span>();<span class="comment">//这里是通过window对象完成bar方法的调用</span></span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">a</span>;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">method</span>()); <span class="comment">// 120</span></span><br></pre></td></tr></table></figure>



<p>第二：如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num = <span class="number">10</span>;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="comment">//给全局变量重新赋值</span></span><br><span class="line">     num = <span class="number">20</span>;</span><br><span class="line">     <span class="comment">// 实例变量</span></span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">num</span> = <span class="number">30</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getNum</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">num</span>;</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="title function_">getNum</span>()); <span class="comment">// 30</span></span><br></pre></td></tr></table></figure>



<p>第三：如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">fn</span>: fn,</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="title function_">fn</span>(); <span class="comment">//window</span></span><br><span class="line">  obj.<span class="title function_">fn</span>(); <span class="comment">//obj</span></span><br></pre></td></tr></table></figure>

<p>第四：如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> fullName = <span class="string">&quot;language&quot;</span>;</span><br><span class="line">     <span class="keyword">var</span> obj = &#123;</span><br><span class="line">       <span class="attr">fullName</span>: <span class="string">&quot;javascript&quot;</span>,</span><br><span class="line">       <span class="attr">prop</span>: &#123;</span><br><span class="line">         <span class="attr">getFullName</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">fullName</span>;</span><br><span class="line">         &#125;,</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">prop</span>.<span class="title function_">getFullName</span>()); <span class="comment">// undefined</span></span><br><span class="line">     <span class="keyword">var</span> test = obj.<span class="property">prop</span>.<span class="property">getFullName</span>; <span class="comment">// language</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">test</span>());</span><br></pre></td></tr></table></figure>



<p>第五：如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> val = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">var</span> json = &#123;</span><br><span class="line">  <span class="attr">val</span>: <span class="number">10</span>,</span><br><span class="line">  <span class="attr">dbl</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    val *= <span class="number">2</span>; <span class="comment">//这里由于前面没有添加this,也就是没有写成this.val,所以这里的val指向了全局变量</span></span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">json.<span class="title function_">dbl</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(json.<span class="property">val</span> + val); <span class="comment">// 12</span></span><br></pre></td></tr></table></figure>



<p>如果将上面的题目修改成如下的形式：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> val = <span class="number">1</span></span><br><span class="line"><span class="keyword">var</span> json = &#123;</span><br><span class="line">  <span class="attr">val</span>: <span class="number">10</span>,</span><br><span class="line">  <span class="attr">dbl</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">val</span> *= <span class="number">2</span> <span class="comment">//20</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">json.<span class="title function_">dbl</span>() </span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(json.<span class="property">val</span> + val)<span class="comment">//21  20+1=21</span></span><br></pre></td></tr></table></figure>

<p>第六，如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num = <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">var</span> obj = &#123; <span class="attr">num</span>: <span class="number">20</span> &#125;;</span><br><span class="line">    obj.<span class="property">fn</span> = (<span class="keyword">function</span> (<span class="params">num</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">num</span> = num * <span class="number">3</span>;</span><br><span class="line">      num++;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">n</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">num</span> += n;</span><br><span class="line">        num++;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;)(obj.<span class="property">num</span>);</span><br><span class="line">    <span class="keyword">var</span> fn = obj.<span class="property">fn</span>;</span><br><span class="line">    <span class="title function_">fn</span>(<span class="number">5</span>);</span><br><span class="line">    obj.<span class="title function_">fn</span>(<span class="number">10</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(num, obj.<span class="property">num</span>);</span><br></pre></td></tr></table></figure>



<p>第七：<code>this</code> 指向<code>call()</code>函数，<code>apply()</code>函数，<code>bind()</code>函数调用后重新绑定的对象。</p>
<p>我们知道通过<code>call()</code>函数，<code>apply()</code>函数，<code>bind()</code>函数可以改变函数执行的主体，如果函数中存在<code>this</code>关键字，则<code>this</code>指向<code>call()</code>函数，<code>apply()</code>函数，<code>bind()</code>函数处理后的对象。</p>
<p>代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//全局变量</span></span><br><span class="line">     <span class="keyword">var</span> value = <span class="number">10</span>;</span><br><span class="line">     <span class="keyword">var</span> obj = &#123;</span><br><span class="line">       <span class="attr">value</span>: <span class="number">20</span>,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="comment">// 全局函数 </span></span><br><span class="line">     <span class="keyword">var</span> method = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">value</span>);</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="title function_">method</span>(); <span class="comment">// 10</span></span><br><span class="line">     method.<span class="title function_">call</span>(obj); <span class="comment">// 20</span></span><br><span class="line">     method.<span class="title function_">apply</span>(obj); <span class="comment">// 20</span></span><br><span class="line">     <span class="keyword">var</span> newMethod = method.<span class="title function_">bind</span>(obj);</span><br><span class="line">     <span class="title function_">newMethod</span>(); <span class="comment">// 20</span></span><br></pre></td></tr></table></figure>



<p>下面我们再来看一段代码，看一下对应的执行结果：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>获取用户信息<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> userInfo = &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">data</span>: [</span></span><br><span class="line"><span class="language-javascript">          &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;,</span></span><br><span class="line"><span class="language-javascript">          &#123; <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>, <span class="attr">age</span>: <span class="number">21</span> &#125;,</span></span><br><span class="line"><span class="language-javascript">        ],</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">getUserInfo</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">var</span> index = <span class="number">1</span>;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">data</span>[index].<span class="property">userName</span> + <span class="string">&quot; &quot;</span> + <span class="variable language_">this</span>.<span class="property">data</span>[index].<span class="property">age</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      btn.<span class="property">onclick</span> = userInfo.<span class="property">getUserInfo</span>;</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>修改后的代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line">   <span class="comment">//   btn.onclick = userInfo.getUserInfo;</span></span><br><span class="line">   btn.<span class="property">onclick</span> = userInfo.<span class="property">getUserInfo</span>.<span class="title function_">bind</span>(userInfo);</span><br></pre></td></tr></table></figure>



<p>第八、如下程序的输出结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;button id=<span class="string">&quot;btn&quot;</span>&gt;获取用户信息&lt;/button&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">var</span> userInfo = &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">data</span>: [</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#123; <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>, <span class="attr">age</span>: <span class="number">21</span> &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    ],</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">getUserInfo</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">p</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="comment">//   btn.onclick = userInfo.getUserInfo;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  btn.<span class="property">onclick</span> = userInfo.<span class="property">getUserInfo</span>.<span class="title function_">bind</span>(userInfo);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>



<p>修改后的代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="keyword">var</span> userInfo = &#123;</span><br><span class="line">        <span class="attr">data</span>: [</span><br><span class="line">          &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;,</span><br><span class="line">          &#123; <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>, <span class="attr">age</span>: <span class="number">21</span> &#125;,</span><br><span class="line">        ],</span><br><span class="line">        <span class="attr">getUserInfo</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">var</span> that = <span class="variable language_">this</span>;<span class="comment">//保存this</span></span><br><span class="line">          <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">p</span>) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(that);<span class="comment">//这里的that 指的就是当前的userInfo对象。</span></span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line">      <span class="comment">//   btn.onclick = userInfo.getUserInfo;</span></span><br><span class="line">      btn.<span class="property">onclick</span> = userInfo.<span class="property">getUserInfo</span>.<span class="title function_">bind</span>(userInfo);</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>或者是修改成箭头函数</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userInfo = &#123;</span><br><span class="line">   <span class="attr">data</span>: [</span><br><span class="line">     &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>, <span class="attr">age</span>: <span class="number">20</span> &#125;,</span><br><span class="line">     &#123; <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span>, <span class="attr">age</span>: <span class="number">21</span> &#125;,</span><br><span class="line">   ],</span><br><span class="line">   <span class="attr">getUserInfo</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="comment">//   var that = this;</span></span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">data</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">p</span>) =&gt;</span> &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">     &#125;);</span><br><span class="line">   &#125;,</span><br><span class="line"> &#125;;</span><br><span class="line"> <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line"> <span class="comment">//   btn.onclick = userInfo.getUserInfo;</span></span><br><span class="line"> btn.<span class="property">onclick</span> = userInfo.<span class="property">getUserInfo</span>.<span class="title function_">bind</span>(userInfo);</span><br></pre></td></tr></table></figure>



<h2 id="13、call-函数，apply-函数，bind-函数的使用与区别"><a href="#13、call-函数，apply-函数，bind-函数的使用与区别" class="headerlink" title="13、call()函数，apply( )函数，bind( )函数的使用与区别"></a>13、call()函数，apply( )函数，bind( )函数的使用与区别</h2><p>在前面我们简单的说过<code>call( )</code>函数，<code>apply( )</code>函数，<code>bind( )</code>函数，的作用。</p>
<p><code>call( )</code>函数，<code>apply( )</code>函数，<code>bind( )</code>函数,的作用都是改变<code>this</code>的指向，但是在使用方式上是有一定的区别的。</p>
<p>下面我们分别来看一下它们各自的使用方式：</p>
<h3 id="call-函数的基本使用"><a href="#call-函数的基本使用" class="headerlink" title="call( )函数的基本使用"></a><code>call( )</code>函数的基本使用</h3><p>基本语法如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span>.<span class="title function_">call</span>(thisObj,arg1,arg2,...)</span><br></pre></td></tr></table></figure>

<p><code>function</code>表示的是：需要调用的函数。</p>
<p><code>thisObj</code>表示：<code>this</code>指向的对象，也就是<code>this</code>将指向<code>thisObj</code>这个参数，如果<code>thisObj</code>的值为<code>null</code>或者是<code>undefined</code>,则<code>this</code>指向的是全局对象。</p>
<p><code>arg1,arg2,..</code>表示：调用的函数需要的参数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(a + b);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">sub</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(a - b);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   add.<span class="title function_">call</span>(sub, <span class="number">3</span>, <span class="number">1</span>);<span class="comment">// 调用add方法，但是add方法中的this指向的是sub,最终的输出结果是4</span></span><br></pre></td></tr></table></figure>

<h3 id="apply-函数的基本使用"><a href="#apply-函数的基本使用" class="headerlink" title="apply( )函数的基本使用"></a><code>apply( )</code>函数的基本使用</h3><p><code>apply()</code>函数的作用与<code>call()</code>函数的作用是一样的，不同的是在传递参数的时候有一定的差别</p>
<p>语法格式如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span>.<span class="title function_">apply</span>(thisObj,[argsArray])</span><br></pre></td></tr></table></figure>

<p><code>function</code>表示的是：需要调用的函数。</p>
<p><code>thisObj</code>:<code>this</code>指向的对象，也就是<code>this</code>将指向<code>thisObj</code>这个参数，如果<code>thisObj</code>的值为<code>null</code>或者是<code>undefined</code>,则<code>this</code>指向的是全局对象。</p>
<p><code>[argsArray]</code>:表示的是函数需要的参数会通过数组的形式进行传递,如果传递的不是数组或者是arguments对象，会抛出异常。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>); <span class="comment">// 这里指向的是sub</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a + b);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">sub</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a - b);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    add.<span class="title function_">apply</span>(sub, [<span class="number">3</span>, <span class="number">1</span>]); </span><br></pre></td></tr></table></figure>

<h3 id="bind函数的基本使用"><a href="#bind函数的基本使用" class="headerlink" title="bind函数的基本使用"></a><code>bind</code>函数的基本使用</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span>.<span class="title function_">bind</span>(thisObj,arg1,arg2,...)</span><br></pre></td></tr></table></figure>

<p>通过上面语法格式，可以看出<code>bind</code>函数与<code>call</code>函数的参数是一样的。</p>
<p>不同 的是<code>bind</code>函数会返回一个新的函数，可以在任何时候进行调用。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>); <span class="comment">// 这里指向的是sub</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(a + b);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sub</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(a - b);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> newFun = add.<span class="title function_">bind</span>(sub, <span class="number">3</span>, <span class="number">1</span>); <span class="comment">//bind 返回的是一个新的函数。</span></span><br><span class="line"><span class="title function_">newFun</span>();<span class="comment">//完成对add函数的调用，同时this指向了sub</span></span><br></pre></td></tr></table></figure>

<h3 id="三个函数的比较"><a href="#三个函数的比较" class="headerlink" title="三个函数的比较"></a>三个函数的比较</h3><p>通过前面对三个函数的基本使用，可以看出，它们共同点就是改变<code>this</code>的指向。</p>
<p>不同点：</p>
<p><code>call()</code>函数与<code>apply()</code>函数，会立即执行函数的调用，而<code>bind</code>返回的是一个新的函数，可以在任何时候进行调用。</p>
<p><code>call()</code>函数与<code>bind</code>函数的参数是一样的，而<code>apply</code>函数第二个参数是一个数组或者是<code>arguments</code>对象。</p>
<h3 id="应用场景-1"><a href="#应用场景-1" class="headerlink" title="应用场景"></a>应用场景</h3><p>这里，我们重点看一下，关于<code>call()</code>函数，<code>bind()</code>函数，<code>apply()</code>函数的应用场景。</p>
<p><strong>求数组中的最大值与最小值</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">3</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">1</span>, <span class="number">9</span>];</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="property">max</span>.<span class="title function_">apply</span>(<span class="literal">null</span>, arr));</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="property">min</span>.<span class="title function_">apply</span>(<span class="literal">null</span>, arr));</span><br></pre></td></tr></table></figure>



<p><strong>将<code>arguments</code>转换成数组</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> arr = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>);</span><br><span class="line">     arr.<span class="title function_">push</span>(<span class="number">6</span>);</span><br><span class="line">     <span class="keyword">return</span> arr;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">fn</span>(<span class="number">1</span>, <span class="number">2</span>));</span><br></pre></td></tr></table></figure>



<p><strong>继承的实现</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, userAge</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">userAge</span> = userAge;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Student</span>(<span class="params">name, age, gender</span>) &#123;</span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, name, age);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">gender</span> = gender;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Student</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">20</span>, <span class="string">&quot;男&quot;</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(</span><br><span class="line">        <span class="string">&quot;userName=&quot;</span> +</span><br><span class="line">          student.<span class="property">userName</span> +</span><br><span class="line">          <span class="string">&quot;,userAge=&quot;</span> +</span><br><span class="line">          student.<span class="property">userAge</span> +</span><br><span class="line">          <span class="string">&quot;,gender=&quot;</span> +</span><br><span class="line">          student.<span class="property">gender</span></span><br><span class="line">      );</span><br></pre></td></tr></table></figure>



<p><strong>改变匿名函数的<code>this</code>指向</strong></p>
<p>首先看一下如下程序的执行结果：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = [</span><br><span class="line">      &#123; <span class="attr">id</span>: <span class="number">1</span>, <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;,</span><br><span class="line">      &#123; <span class="attr">id</span>: <span class="number">2</span>, <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span> &#125;,</span><br><span class="line">    ];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; person.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      (<span class="keyword">function</span> (<span class="params">i</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">print</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">print</span>();</span><br><span class="line">      &#125;)(i);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<p>具体的实现方式如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = [</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">1</span>, <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">id</span>: <span class="number">2</span>, <span class="attr">userName</span>: <span class="string">&quot;lisi&quot;</span> &#125;,</span><br><span class="line">  ];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; person.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    (<span class="keyword">function</span> (<span class="params">i</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">print</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="title function_">print</span>();</span><br><span class="line">    &#125;.<span class="title function_">call</span>(person[i], i));</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>



<h3 id="手写call、apply及bind函数"><a href="#手写call、apply及bind函数" class="headerlink" title="手写call、apply及bind函数"></a>手写call、apply及bind函数</h3><p><strong><code>call</code>方法的实现</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">myCall</span> = <span class="keyword">function</span> (<span class="params">context</span>) &#123;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">var</span> args = [...<span class="variable language_">arguments</span>].<span class="title function_">slice</span>(<span class="number">1</span>);</span><br><span class="line"> </span><br><span class="line">  context = context || <span class="variable language_">window</span>;</span><br><span class="line">  </span><br><span class="line">  context.<span class="property">fn</span> = <span class="variable language_">this</span>;</span><br><span class="line">     </span><br><span class="line">  <span class="keyword">var</span> result = context.<span class="title function_">fn</span>(...args);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 + num2);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Sub</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 - num2);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Add</span>.<span class="title function_">myCall</span>(<span class="title class_">Sub</span>, <span class="number">6</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>



<p><strong><code>apply</code>函数的实现</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">myApply</span> = <span class="keyword">function</span> (<span class="params">context</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> result = <span class="literal">null</span>;</span><br><span class="line">       context = context || <span class="variable language_">window</span>;</span><br><span class="line">       context.<span class="property">fn</span> = <span class="variable language_">this</span>;</span><br><span class="line">       <span class="keyword">if</span> (<span class="variable language_">arguments</span>[<span class="number">1</span>]) &#123;</span><br><span class="line">         <span class="comment">// console.log(&quot;arguments=&quot;, arguments[1]);// arguments= (2) [6, 3]</span></span><br><span class="line">         result = context.<span class="title function_">fn</span>(...<span class="variable language_">arguments</span>[<span class="number">1</span>]);</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">         result = context.<span class="title function_">fn</span>();</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> result;</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 + num2);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Sub</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 - num2);</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Add</span>.<span class="title function_">myApply</span>(<span class="title class_">Sub</span>, [<span class="number">6</span>, <span class="number">3</span>]);</span><br></pre></td></tr></table></figure>





<p><strong><code>bind</code>函数的实现</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">myBind</span> = <span class="keyword">function</span> (<span class="params">context</span>) &#123;</span><br><span class="line">     <span class="comment">// 获取参数</span></span><br><span class="line">     <span class="keyword">var</span> args = [...<span class="variable language_">arguments</span>].<span class="title function_">slice</span>(<span class="number">1</span>), <span class="comment">// [1,5]</span></span><br><span class="line">       fn = <span class="variable language_">this</span>;</span><br><span class="line">     <span class="comment">// console.log(this);//Add</span></span><br><span class="line">     <span class="keyword">return</span> <span class="keyword">function</span> <span class="title function_">Fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="comment">// console.log(this); //Window</span></span><br><span class="line">       <span class="keyword">return</span> fn.<span class="title function_">apply</span>(context, args);</span><br><span class="line">     &#125;;</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 + num2);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Sub</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 - num2);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> newFun = <span class="title class_">Add</span>.<span class="title function_">myBind</span>(<span class="title class_">Sub</span>, <span class="number">1</span>, <span class="number">5</span>);</span><br><span class="line">   <span class="title function_">newFun</span>();</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>); <span class="comment">// 这里指向的是sub</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a + b);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">sub</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(a - b);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> newFun = add.<span class="title function_">bind</span>(sub, <span class="number">3</span>); <span class="comment">//bind 返回的是一个新的函数。</span></span><br><span class="line">    <span class="title function_">newFun</span>(<span class="number">2</span>); <span class="comment">//完成对add函数的调用，同时this指向了sub</span></span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>下面，我们就实现一下关于<code>myBind</code>方法参数的模拟。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">myBind</span> = <span class="keyword">function</span> (<span class="params">context</span>) &#123;</span><br><span class="line">    <span class="comment">// 获取参数</span></span><br><span class="line">    <span class="keyword">var</span> args = [...<span class="variable language_">arguments</span>].<span class="title function_">slice</span>(<span class="number">1</span>),</span><br><span class="line">      fn = <span class="variable language_">this</span>;</span><br><span class="line">    <span class="comment">// console.log(this);//Add</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> <span class="title function_">Fn</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="comment">// console.log(this); //Window</span></span><br><span class="line">      <span class="comment">//这里是调用bind函数的时候传递的参数，将其转换成数组</span></span><br><span class="line">      <span class="keyword">var</span> bindArgs = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>);</span><br><span class="line">      <span class="comment">//下面完成参数的拼接</span></span><br><span class="line">      <span class="keyword">return</span> fn.<span class="title function_">apply</span>(context, args.<span class="title function_">concat</span>(bindArgs));</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">Add</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 + num2);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">Sub</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(num1 - num2);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> newFun = <span class="title class_">Add</span>.<span class="title function_">myBind</span>(<span class="title class_">Sub</span>, <span class="number">1</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">newFun</span>(<span class="number">8</span>));</span><br></pre></td></tr></table></figure>



<h2 id="14、回调函数有什么缺点"><a href="#14、回调函数有什么缺点" class="headerlink" title="14、回调函数有什么缺点"></a>14、回调函数有什么缺点</h2><p>在<code>JavaScript</code>编程过程中，我们经常会写回调函数。</p>
<p>我们知道在<code>JavaScript</code>中函数也是一种对象，对象可以作为参数传递给函数，因此函数也可以作为参数传递给另外一个函数，这个作为参数的函数就是回调函数。</p>
<p>例如，如下的代码示例：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> btn=<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;btn&#x27;</span>);</span><br><span class="line">btn.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params">event</span>)&#123;</span><br><span class="line">    </span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>回调函数有一个比较严重的问题，就是很容易出现回调地狱的问题。也就是实现了回调函数不断的嵌套。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>)</span><br><span class="line">    </span><br><span class="line">        &#125;,<span class="number">3000</span>)</span><br><span class="line">    </span><br><span class="line">    &#125;,<span class="number">2000</span>)</span><br><span class="line">&#125;,<span class="number">1000</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>以上的代码就是典型的回调地狱的问题，这样的代码是非常不利于阅读和维护的。</p>
<p>所以在<code>ES6</code>中提供了<code>Promise</code>以及<code>async/await</code>来解决地狱回调的问题。关于这块内容</p>
<h2 id="15、-为什么函数被称为一等公民？"><a href="#15、-为什么函数被称为一等公民？" class="headerlink" title="15、 为什么函数被称为一等公民？"></a>15、 为什么函数被称为一等公民？</h2><p>JavaScript 语言将函数看作一种值，与其它值（数值、字符串、布尔值等等）地位相同。凡是可以使用值的地方，就能使用函数。比如，可以把<strong>函数赋值给变量和对象的属性</strong>，也可以当作<strong>参数传入其他函数</strong>，或者<strong>作为函数的结果返回</strong>。</p>
<p>同时函数还可以作为类的构造函数，完成对象实例的创建。所以说，这种多重身份让<code>JavaScript</code>中的函数变得非常重要，所以说函数被称为一等公民。</p>
<h1 id><a href="#" class="headerlink" title></a></h1><h1 id="四、对象"><a href="#四、对象" class="headerlink" title="四、对象"></a>四、对象</h1><h2 id="1、对象的属性"><a href="#1、对象的属性" class="headerlink" title="1、对象的属性"></a>1、对象的属性</h2><p>给对象添加属性非常的简单如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person=&#123;</span><br><span class="line">    <span class="attr">userName</span>:<span class="string">&#x27;zhangsan&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果想修改属性的特性，可以通过<code>Object.defineProperty()</code>来完成。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123;</span><br><span class="line">      <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(person, <span class="string">&quot;userName&quot;</span>, &#123;</span><br><span class="line">      <span class="attr">writable</span>: <span class="literal">false</span>,</span><br><span class="line">    &#125;);</span><br><span class="line">    person.<span class="property">userName</span> = <span class="string">&quot;lisi&quot;</span>; <span class="comment">//无法完成值的修改</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">userName</span>); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>

<p>我们可以给<code>Object.defineProperty</code>添加<code>getter()</code>函数和<code>setter( )</code>函数，这两个函数可以实现对象的私有属性，私有属性不对外公布，如果想要对私有属性进行读取和写入，可以通过<code>getter()</code>函数和<code>setter( )</code>函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123;</span><br><span class="line">       <span class="attr">_age</span>: <span class="number">20</span>, <span class="comment">// _age表示私有属性</span></span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(person, <span class="string">&quot;age&quot;</span>, &#123;</span><br><span class="line">       <span class="attr">get</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_age</span>;</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="comment">//在给私有属性赋值的时候，完成对应的校验功能</span></span><br><span class="line">       <span class="attr">set</span>: <span class="keyword">function</span> (<span class="params">value</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (value &gt;= <span class="number">18</span>) &#123;</span><br><span class="line">           <span class="variable language_">this</span>.<span class="property">_age</span> = value;</span><br><span class="line">           <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;可以浏览该网站&quot;</span>);</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;不可以浏览该网站&quot;</span>);</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">age</span>); <span class="comment">//20</span></span><br><span class="line">     person.<span class="property">age</span> = <span class="number">12</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">age</span>); <span class="comment">//20</span></span><br><span class="line">     person.<span class="property">age</span> = <span class="number">30</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">age</span>); <span class="comment">// 30</span></span><br></pre></td></tr></table></figure>

<p>关于<code>Object.defineProperty</code>更详细的内容，可以参考<code>vue</code>响应式原理的课程。</p>
<h2 id="2、属性访问方式的区别"><a href="#2、属性访问方式的区别" class="headerlink" title="2、属性访问方式的区别"></a>2、属性访问方式的区别</h2><p>我们知道访问对象中的属性，有两种方式。</p>
<p>第一种方式:通过‘.’来访问。</p>
<p>第二种方式:通过‘[ ]’来访问属性。</p>
<p>两种方式有什么区别呢？</p>
<p>第一：使用方括号来访问属性，可以借助于变量来实现。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">var</span> myName = <span class="string">&quot;userName&quot;</span>;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(person[myName]);</span><br></pre></td></tr></table></figure>

<p>第二：使用方括号来访问属性，也可以通过数字来做属性。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> person = &#123;&#125;;</span><br><span class="line">    person[<span class="number">1</span>] = <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person[<span class="number">1</span>]);</span><br></pre></td></tr></table></figure>

<h2 id="3、创建对象有哪几种方式"><a href="#3、创建对象有哪几种方式" class="headerlink" title="3、创建对象有哪几种方式"></a>3、创建对象有哪几种方式</h2><p><strong>字面量方式创建对象</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> userInfo = &#123;</span><br><span class="line">       <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">       <span class="attr">userAge</span>: <span class="number">18</span>,</span><br><span class="line">       <span class="attr">getUserInfo</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + <span class="variable language_">this</span>.<span class="property">userAge</span>);</span><br><span class="line">       &#125;, </span><br><span class="line">     &#125;;</span><br><span class="line">     userInfo.<span class="title function_">getUserInfo</span>();</span><br></pre></td></tr></table></figure>

<p>字面量创建对象比较简单，但是问题也比较突出，每次只能创建一个对象，复用性比较差，如果需要创建多个对象，代码冗余比较高。</p>
<p><strong>通过工厂模式创建对象</strong></p>
<p>工厂模式是一个比较重要的设计模式，该模式提供了一个函数，在该函数中完成对象的创建。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">createUser</span>(<span class="params">userName, userAge</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> o = <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">       o.<span class="property">userName</span> = userName;</span><br><span class="line">       o.<span class="property">userAge</span> = userAge;</span><br><span class="line">       o.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + <span class="variable language_">this</span>.<span class="property">userAge</span>);</span><br><span class="line">       &#125;;</span><br><span class="line">       <span class="keyword">return</span> o;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> user1 = <span class="title function_">createUser</span>(<span class="string">&quot;wangwu&quot;</span>, <span class="number">20</span>);</span><br><span class="line">     <span class="keyword">var</span> user2 = <span class="title function_">createUser</span>(<span class="string">&quot;lisi&quot;</span>, <span class="number">20</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(user1.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + user2.<span class="property">userName</span>);</span><br></pre></td></tr></table></figure>

<p>通过工厂模式创建对象，解决了字面量创建对象的问题，也就是当创建多个相似对象的时候代码重复的问题。</p>
<p>但是问题是，所创建的所有对象都是<code>Object</code>类型，无法进一步的区分对象的具体类型是什么。</p>
<p><strong>通过构造函数创建对象</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, userAge</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userAge</span> = userAge;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + <span class="variable language_">this</span>.<span class="property">userAge</span>);</span><br><span class="line">       &#125;;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">19</span>);</span><br><span class="line">     p.<span class="title function_">sayHi</span>();</span><br></pre></td></tr></table></figure>

<p>构造函数创建对象的优点：解决了工厂模式中对象类型无法识别的问题，也就是说通过构造函数创建的对象可以确定其所属的类型。</p>
<p>但是通过构造函数创建对象的问题：</p>
<p>在使用构造函数创建对象的时候，每个方法都会在创建对象时重新创建一遍，也就是说，根据<code>Person</code>构造函数每创建一个对象，我们就会创建一个<code>sayHi</code>方法，但它们做的事情是一样的，因此会造成内存的浪费。</p>
<p><strong>通过原型模式创建对象</strong></p>
<p>我们知道，每个函数都有一个<code>prototype</code>属性，这个属性指向函数的原型对象，而所谓的通过原型模式创建对象就是将属性和方法添加到<code>prototype</code>属性上。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">userName</span> = <span class="string">&quot;wangwu&quot;</span>;</span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">userAge</span> = <span class="number">20</span>;</span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + <span class="variable language_">this</span>.<span class="property">userAge</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">var</span> person1 = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">    person1.<span class="title function_">sayHi</span>();</span><br><span class="line">    <span class="keyword">var</span> person2 = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(person1.<span class="property">sayHi</span> === person2.<span class="property">sayHi</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>

<p>通过上面的代码，我们可以发现，使用基于原型模式创建的对象，它的属性和方法都是相等的，也就是说不同的对象会共享原型上的属性和方法，这样我们就解决了<code>构造函数</code>创建对象的问题。</p>
<p>但是这种方式创建的对象也是有问题的，因为所有的对象都是共享相同的属性，所以改变一个对象的属性值，会引起其他对象属性值的改变。而这种情况是我们不允许的，因为这样很容易造成数据的混乱。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">userName</span> = <span class="string">&quot;wangwu&quot;</span>;</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">userAge</span> = <span class="number">20</span>;</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">arr</span> = [<span class="number">1</span>, <span class="number">2</span>];</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span> + <span class="string">&quot;:&quot;</span> + <span class="variable language_">this</span>.<span class="property">userAge</span>);</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">   <span class="keyword">var</span> p2 = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">userName</span>);</span><br><span class="line">   p2.<span class="property">userName</span> = <span class="string">&quot;zhangsan&quot;</span>;</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">userName</span>); <span class="comment">//wangwu,基本数据类型不受影响</span></span><br><span class="line">   p1.<span class="property">arr</span>.<span class="title function_">push</span>(<span class="number">3</span>);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">arr</span>); <span class="comment">// [1,2,3]</span></span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(p2.<span class="property">arr</span>); <span class="comment">// [1,2,3]</span></span><br><span class="line">   <span class="comment">//引用类型受影响</span></span><br></pre></td></tr></table></figure>



<p><strong>组合使用构造函数模式和原型模式</strong></p>
<p>通过构造函数和原型模式创建对象是比较常用的一种方式。</p>
<p>在构造函数中定义对象的属性，而在原型对象中定义对象共享的属性和方法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//在构造函数中定义对象的属性</span></span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, userAge</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">userAge</span> = userAge;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//在原型对象中添加共享的方法</span></span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">userName</span>;</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">21</span>);</span><br><span class="line">      <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;lisi&quot;</span>, <span class="number">22</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="title function_">sayHi</span>());</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">sayHi</span>());</span><br><span class="line">      <span class="comment">// 不同对象共享相同的函数，所以经过比较发现是相等的。</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="property">sayHi</span> === p1.<span class="property">sayHi</span>);</span><br><span class="line">      <span class="comment">//修改p对象的userName属性的值，但是不会影响到p1对象的userName属性的值</span></span><br><span class="line">      p.<span class="property">userName</span> = <span class="string">&quot;admin&quot;</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">sayHi</span>());</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="title function_">sayHi</span>());</span><br></pre></td></tr></table></figure>

<p>通过构造函数与原型模式组合创建对象的好处就是：每个对象都有自己的属性值，也就是拥有一份自己的实例属性的副本，同时又共享着方法的引用，最大限度的节省了内存。</p>
<p><strong>使用动态原型模式创建对象</strong></p>
<p>所谓的使用动态原型模式创建对象，其实就是将所有的内容都封装到构造函数中，而在构造函数中通过判断只初始化一次原型。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName, userAge</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userAge</span> = userAge;</span><br><span class="line">       <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">this</span>.<span class="property">sayHi</span> !== <span class="string">&quot;function&quot;</span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;abc&quot;</span>); <span class="comment">//只输出一次</span></span><br><span class="line">         <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHi</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">           <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">         &#125;;</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">21</span>);</span><br><span class="line">     <span class="keyword">var</span> person1 = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>, <span class="number">21</span>);</span><br><span class="line">     person.<span class="title function_">sayHi</span>();</span><br><span class="line">     person1.<span class="title function_">sayHi</span>();</span><br></pre></td></tr></table></figure>

<p>通过上面的代码可以看出，我们将所有的内容写在了构造函数中，并且在构造函数中通过判断只初始化一次原型，而且只在第一次生成实例的时候进行原型的设置。这种方式创建的对象与构造函数和原型混合模式创建的对象功能上是相同的。</p>
<h2 id="4、对象拷贝"><a href="#4、对象拷贝" class="headerlink" title="4、对象拷贝"></a>4、对象拷贝</h2><p>拷贝指的就是将某个变量的值复制给另外一个变量的过程，关于拷贝可以分为浅拷贝与深拷贝。</p>
<p>针对不同的数据类型，浅拷贝与深拷贝会有不同的表现，主要表现于基本数据类型和引用数据类型在内存中存储的值不同。</p>
<p>对于基本数据类型，变量存储的是值本身，</p>
<p>对于引用数据类型，变量存储的是值在内存中的地址，如果有多个变量同时指向同一个内存地址，其中对一个变量的值进行修改以后，其它的变量也会受到影响。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr=[<span class="number">1</span>,<span class="number">23</span>,<span class="number">33</span>]</span><br><span class="line"><span class="keyword">var</span> arr2=arr</span><br><span class="line">arr2[<span class="number">0</span>]=<span class="number">10</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr) <span class="comment">//  [10, 23, 33]</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们把<code>arr</code>赋值给了<code>arr2</code>,然后修改<code>arr2</code>的值，但是<code>arr</code>也受到了影响。</p>
<p>正是由于数据类型的不同，导致在进行浅拷贝与深拷贝的时候首先的效果是不一样的。</p>
<p><strong>基本数据类型不管是浅拷贝还是深拷贝都是对值的本身的拷贝。对拷贝后值的修改不会影响到原始的值。</strong></p>
<p><strong>对于引用数据类型进行浅拷贝，拷贝后的值的修改会影响到原始的值，如果执行的是深拷贝，则拷贝的对象和原始对象之间相互独立，互不影响。</strong></p>
<p>所以，这里我们可以总结出什么是浅拷贝，什么是深拷贝。</p>
<p>浅拷贝：如果一个对象中的属性是基本数据类型，拷贝的就是基本类型的值，如果属性是引用类型，拷贝的就是内存地址，也就是拷贝后的内容与原始内容指向了同一个内存地址，这样拷贝后的值的修改会影响到原始的值。</p>
<p>深拷贝：如果一个对象中的属性是基本数据类型，拷贝的也是基本类型的值，如果属性是引用类型，就将其从内存中完整的拷贝一份出来，并且会在堆内存中开辟出一个新的区域存来进行存放，而且拷贝的对象和原始对象之间相互独立，互不影响。</p>
<h3 id="浅拷贝"><a href="#浅拷贝" class="headerlink" title="浅拷贝"></a>浅拷贝</h3><p>下面我们先来看一下<strong>浅拷贝</strong>的内容</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123; <span class="attr">a</span>: <span class="number">1</span>, <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>], <span class="attr">o</span>: &#123; <span class="attr">name</span>: <span class="string">&quot;zhangsan&quot;</span> &#125; &#125;;</span><br><span class="line">     <span class="keyword">var</span> shallowObj = <span class="title function_">shallowCopy</span>(obj);</span><br><span class="line"></span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">shallowCopy</span>(<span class="params">src</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> dst = &#123;&#125;;</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> prop <span class="keyword">in</span> src) &#123;</span><br><span class="line">         <span class="keyword">if</span> (src.<span class="title function_">hasOwnProperty</span>(prop)) &#123;</span><br><span class="line">           dst[prop] = src[prop];</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> dst;</span><br><span class="line">     &#125;</span><br><span class="line">     obj.<span class="property">o</span>.<span class="property">name</span> = <span class="string">&quot;lisi&quot;</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(shallowObj.<span class="property">o</span>.<span class="property">name</span>); <span class="comment">//lisi,值受到了影响</span></span><br><span class="line">     obj.<span class="property">arr</span>[<span class="number">0</span>] = <span class="number">20</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(shallowObj.<span class="property">arr</span>[<span class="number">0</span>]); <span class="comment">//20，值受到了影响</span></span><br><span class="line">     obj.<span class="property">a</span> = <span class="number">10</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(shallowObj.<span class="property">a</span>); <span class="comment">// 1,值没有收到影响</span></span><br></pre></td></tr></table></figure>



<p>除了以上方式实现浅拷贝以外，还可以通过<code>ES6</code>中的<code>Object.assign()</code>函数来实现，该函数可以将源对象中的可枚举的属性复制到目标对象中。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123; <span class="attr">a</span>: <span class="number">1</span>, <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>], <span class="attr">o</span>: &#123; <span class="attr">name</span>: <span class="string">&quot;zhangsan&quot;</span> &#125; &#125;;</span><br><span class="line">     <span class="keyword">var</span> result = &#123;&#125;;</span><br><span class="line">     <span class="comment">//将obj对象拷贝给result对象</span></span><br><span class="line">     <span class="title class_">Object</span>.<span class="title function_">assign</span>(result, obj);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line">     obj.<span class="property">a</span> = <span class="number">10</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="property">a</span>); <span class="comment">// 1，不受影响</span></span><br><span class="line">     obj.<span class="property">arr</span>[<span class="number">0</span>] = <span class="number">20</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="property">arr</span>[<span class="number">0</span>]); <span class="comment">//20 受影响</span></span><br><span class="line">     obj.<span class="property">o</span>.<span class="property">name</span> = <span class="string">&quot;lisi&quot;</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="property">o</span>.<span class="property">name</span>); <span class="comment">// lisi 受影响</span></span><br></pre></td></tr></table></figure>



<h3 id="深拷贝"><a href="#深拷贝" class="headerlink" title="深拷贝"></a>深拷贝</h3><p>下面，我们来看一下<strong>深拷贝</strong>内容</p>
<p>这里，我们可以使用</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>());</span><br></pre></td></tr></table></figure>

<p>来实现深拷贝。</p>
<p><code>JSON.stringify()</code>可以将对象转换为字符串</p>
<p><code>JSON.parse()</code>可以将字符串反序列为一个对象</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123; <span class="attr">a</span>: <span class="number">1</span>, <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>], <span class="attr">o</span>: &#123; <span class="attr">name</span>: <span class="string">&quot;zhangsan&quot;</span> &#125; &#125;;</span><br><span class="line">     <span class="keyword">var</span> str = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(obj);</span><br><span class="line">     <span class="keyword">var</span> resultObj = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(str);</span><br><span class="line">     obj.<span class="property">a</span> = <span class="number">10</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(resultObj.<span class="property">a</span>); <span class="comment">// 1 不受影响</span></span><br><span class="line">     obj.<span class="property">arr</span>[<span class="number">0</span>] = <span class="number">20</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(resultObj.<span class="property">arr</span>[<span class="number">0</span>]); <span class="comment">// 2 不受影响</span></span><br><span class="line">     obj.<span class="property">o</span>.<span class="property">name</span> = <span class="string">&quot;lisi&quot;</span>;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(resultObj.<span class="property">o</span>.<span class="property">name</span>); <span class="comment">// zhangsan 不受影响</span></span><br></pre></td></tr></table></figure>

<p>以上通过<code>JSON</code>对象，虽然能够实现深拷贝，但是还是有一定的问题的。</p>
<p>第一：无法实现对函数的拷贝</p>
<p>第二：如果对象中存在循环引用，会抛出异常。</p>
<p>第三：对象中的构造函数会指向<code>Object</code>,原型链关系被破坏。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">userName</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = userName;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">     <span class="keyword">var</span> obj = &#123;</span><br><span class="line">       <span class="attr">fn</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;abc&quot;</span>);</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="comment">// 属性o的值为某个对象</span></span><br><span class="line">       <span class="attr">o</span>: person,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">var</span> str = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(obj);</span><br><span class="line">     <span class="keyword">var</span> resultObj = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(str);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;resultObj=&quot;</span>, resultObj); <span class="comment">// 这里丢失了fn属性。因为该属性的值为函数</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(resultObj.<span class="property">o</span>.<span class="property">constructor</span>); <span class="comment">//指向了Object,导致了原型链关系的破坏。</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">o</span>.<span class="property">constructor</span>); <span class="comment">// 这里指向Person构造函数，没有问题</span></span><br></pre></td></tr></table></figure>

<p>下面我们再来看一下循环引用的情况：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">      <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">    &#125;;</span><br><span class="line">    obj.<span class="property">a</span> = obj;</span><br><span class="line">    <span class="keyword">var</span> result = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(obj));</span><br></pre></td></tr></table></figure>

<p>以上的内容会抛出异常。</p>
<p><strong>自己模拟实现深拷贝</strong></p>
<p>这里，我们实现一个简单的深拷贝，当然也可以使用第三方库中的方法来实现深拷贝，例如：可以使用<code>jQuery</code>中的<code>$.extend()</code></p>
<p>在浅拷贝中，我们通过循环将源对象中属性依次添加到目标对象中，而在深拷贝中，需要考虑对象中的属性是否有嵌套的情况（属性的值是否还是一个对象），如果有嵌套可以通过递归的方式来实现，直到属性为基本类型，也就是说，我们需要将源对象各个属性所包含的对象依次采用递归的方式复制到<strong>新对象</strong>上。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params">target</span>) &#123;</span><br><span class="line">       <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">&quot;object&quot;</span>) &#123;</span><br><span class="line">         <span class="keyword">let</span> objTarget = &#123;&#125;;</span><br><span class="line">         <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">             <span class="comment">//通过递归完成拷贝</span></span><br><span class="line">           objTarget[key] = <span class="title function_">clone</span>(target[key]);</span><br><span class="line">         &#125;</span><br><span class="line">         <span class="keyword">return</span> objTarget;</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">         <span class="keyword">return</span> target;</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> obj = &#123;</span><br><span class="line">       <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">       <span class="attr">a</span>: &#123;</span><br><span class="line">         <span class="attr">a1</span>: <span class="string">&quot;hello&quot;</span>,</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">var</span> result = <span class="title function_">clone</span>(obj);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>以上就是一个最简单的深拷贝功能，但是在这段代码中我们只考虑了普通的<code>object</code>,还没有实现数组，所以将上面的代码修改一下，让其能够兼容到数组。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params">target</span>) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">&quot;object&quot;</span>) &#123;</span><br><span class="line">       <span class="comment">//判断target是否为数组</span></span><br><span class="line">       <span class="keyword">let</span> objTarget = <span class="title class_">Array</span>.<span class="title function_">isArray</span>(target) ? [] : &#123;&#125;;</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">         objTarget[key] = <span class="title function_">clone</span>(target[key]);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> objTarget;</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> target;</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> obj = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">     <span class="attr">a</span>: &#123;</span><br><span class="line">       <span class="attr">a1</span>: <span class="string">&quot;hello&quot;</span>,</span><br><span class="line">     &#125;,</span><br><span class="line">     <span class="comment">//添加数组</span></span><br><span class="line">     <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">var</span> result = <span class="title function_">clone</span>(obj);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，添加了<code>  let objTarget = Array.isArray(target) ? [] : &#123;&#125;;</code>判断<code>target</code>是否为数组。</p>
<p>下面我们来看一下循环引用的情况：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params">target</span>) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">&quot;object&quot;</span>) &#123;</span><br><span class="line">       <span class="comment">//判断target是否为数组</span></span><br><span class="line">       <span class="keyword">let</span> objTarget = <span class="title class_">Array</span>.<span class="title function_">isArray</span>(target) ? [] : &#123;&#125;;</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">         objTarget[key] = <span class="title function_">clone</span>(target[key]);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> objTarget;</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> target;</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> obj = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">     <span class="attr">a</span>: &#123;</span><br><span class="line">       <span class="attr">a1</span>: <span class="string">&quot;hello&quot;</span>,</span><br><span class="line">     &#125;,</span><br><span class="line">     <span class="comment">//添加数组</span></span><br><span class="line">     <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">   &#125;;</span><br><span class="line">   obj.<span class="property">o</span> = obj; <span class="comment">//构成了循环引用</span></span><br><span class="line">   <span class="keyword">var</span> result = <span class="title function_">clone</span>(obj);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，添加了<code>obj.o=obj</code>.然后出现了<code>Maximum call stack size exceeded</code></p>
<p>以上的错误表明了递归进入了死循环导致栈内存溢出。</p>
<p>原因是：对象存在循环引用的情况，也就是对象的属性间接或直接引用了自身的情况。</p>
<p>解决的方法：这里我们可以额外开辟一个存储空间，在这个存储空间中存储当前对象和拷贝对象之间的对应关系。</p>
<p>当需要拷贝当前的对象的时候，先去这个存储空间中进行查找，如果没有拷贝过这个对象，执行拷贝操作。如果已经拷贝过这个对象，直接返回，这样就可以解决循环引用的问题。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> map = <span class="keyword">new</span> <span class="title class_">WeakMap</span>();</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params">target</span>) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">&quot;object&quot;</span>) &#123;</span><br><span class="line">       <span class="comment">//判断target是否为数组</span></span><br><span class="line">       <span class="keyword">let</span> objTarget = <span class="title class_">Array</span>.<span class="title function_">isArray</span>(target) ? [] : &#123;&#125;;</span><br><span class="line">       <span class="comment">// 如果有直接返回</span></span><br><span class="line">       <span class="keyword">if</span> (map.<span class="title function_">get</span>(target)) &#123;</span><br><span class="line">         <span class="keyword">return</span> target;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//存储当前对象与拷贝对象的对应关系</span></span><br><span class="line">       map.<span class="title function_">set</span>(target, objTarget);</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">         objTarget[key] = <span class="title function_">clone</span>(target[key]);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> objTarget;</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> target;</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> obj = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">     <span class="attr">a</span>: &#123;</span><br><span class="line">       <span class="attr">a1</span>: <span class="string">&quot;hello&quot;</span>,</span><br><span class="line">     &#125;,</span><br><span class="line">     <span class="comment">//添加数组</span></span><br><span class="line">     <span class="attr">arr</span>: [<span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">   &#125;;</span><br><span class="line">   obj.<span class="property">o</span> = obj; <span class="comment">//构成了循环引用</span></span><br><span class="line">   <span class="keyword">var</span> result = <span class="title function_">clone</span>(obj);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br></pre></td></tr></table></figure>

<p>以上就是一个基本的深拷贝的案例。</p>
<h2 id="5、重写原型对象的问题"><a href="#5、重写原型对象的问题" class="headerlink" title="5、重写原型对象的问题"></a>5、重写原型对象的问题</h2><p><strong>原型对象</strong></p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/constructor.png"></p>
<p>在前面的课程中，我们讲解过原型对象，我们知道每个函数在创建的时候都会有一个<code>prototype</code>属性，它指向函数的原型对象。</p>
<p>在这个对象中可以包含所有实例共享的属性和方法。例如上图中的<code>sayName</code>方法。</p>
<p>同时在每个原型对象上都会增加一个<code>constructor</code>属性，该属性指向<code>prototype</code>属性所在的构造函数，如上图所示。</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/proto.png"></p>
<p>当我们通过<code>new</code>操作符创建一个实例的时候，该实例就有了一个<code>__proto__</code>属性，该属性指向了构造函数的原型对象，如上图所示：</p>
<p>所以说，<code>__proto__</code>属性可以看作是一个连接实例与构造函数的原型对象的桥梁。</p>
<p><strong>所以三者的关系是，每个构造函数都有一个原型对象，原型对象都包含一个指向构造函数的指针，而实例都包含一个指向原型对象的内部指针。</strong>通俗点说就是，实例通过内部指针可以访问到原型对象，原型对象通过constructor指针，又可以找到构造函数。也就是上图体现的内容。</p>
<p>下面我们来看一个问题：<strong>重写原型对象</strong></p>
<p>我们在前面写代码的时候，每次都是为原型对象添加一个属性或者函数时，都是直接给<code>Person.prototype</code>上添加，这种写法比较冗余。</p>
<p>我们可以将属性和方法写成一个字面量对象的形式，然后在赋值给<code>prototype</code>属性。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">     <span class="attr">age</span>: <span class="number">20</span>,</span><br><span class="line">     <span class="attr">sayHi</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">     &#125;,</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">   person.<span class="title function_">sayHi</span>(); <span class="comment">//zhangsan</span></span><br></pre></td></tr></table></figure>

<p>通过执行的结果，依然可以获取到原型对象上属性的值。</p>
<p>当我们把一个字面量对象赋值给<code>prototype</code>属性以后，实际上就是重写了原型对象。</p>
<p>但是这时候，我们打印<code>Person.prototype.constructor</code>的时候，发现不在指向<code>Person</code>这个构造函数,而是指向了<code>Object</code>构造函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">  <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span>,</span><br><span class="line">    <span class="attr">sayHi</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">  person.<span class="title function_">sayHi</span>();</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span>); <span class="comment">// Object</span></span><br></pre></td></tr></table></figure>

<p>原因是：在重写<code>prototype</code>的时候，我们使用字面量创建了一个新的对象，并且这个新的对象中少了<code>constructor</code>属性，</p>
<p>如下图所示</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E9%87%8D%E5%86%99.png"></p>
<p>而我们可以看到在字面量对象中有一个<code>__proto__</code>属性，指向了<code>Object</code>的原型对象,这时，只能去<code>Object</code>原型对象中查找是否有<code>constructor</code>属性，而<code>Object</code>原型对象中的<code>constructor</code>指向的还是<code>Object</code>.所以最终输出结果为<code>Object</code>.</p>
<p>我们怎样避免这种情况呢？</p>
<p>可以在重写原型对象的时候添加<code>constructor</code>属性。这样就不用在去新对象的原型对象中查找<code>constructor</code>属性了。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">        <span class="attr">constructor</span>: <span class="title class_">Person</span>, <span class="comment">//添加constructor</span></span><br><span class="line">        <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">        <span class="attr">age</span>: <span class="number">20</span>,</span><br><span class="line">        <span class="attr">sayHi</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      person.<span class="title function_">sayHi</span>();</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span>);<span class="comment">// Person</span></span><br></pre></td></tr></table></figure>

<p>重写了原型对象以后，还需要注意一个问题，就是在重写原型对象之前，已经生成的对象的实例，无法获取新的原型对象中的属性和方法。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">    <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();<span class="comment">//在重写原型对象之前，生成对象的实例</span></span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">      <span class="attr">constructor</span>: <span class="title class_">Person</span>, <span class="comment">//添加constructor</span></span><br><span class="line">      <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span>,</span><br><span class="line">      <span class="attr">age</span>: <span class="number">20</span>,</span><br><span class="line">      <span class="attr">sayHi</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="comment">//   var person = new Person();</span></span><br><span class="line">    person.<span class="title function_">sayHi</span>(); <span class="comment">//  person.sayHi is not a function,无法获取sayHi函数。</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span>);</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>造成上面错误的原因是：<code>person</code>这个对象指向的是最初的原型对象，而最初的原型对象中是没有<code>sayHi</code>这个方法的。</p>
<p>所以在执行的时候会抛出异常。</p>
<h2 id="6、继承的实现方式有哪些"><a href="#6、继承的实现方式有哪些" class="headerlink" title="6、继承的实现方式有哪些"></a>6、继承的实现方式有哪些</h2><p>关于继承的实现方式，在前面，我们也已经讲解过，这里做一个汇总。</p>
<h3 id="原型链继承"><a href="#原型链继承" class="headerlink" title="原型链继承"></a>原型链继承</h3><p>代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">      <span class="keyword">function</span> <span class="title function_">Animal</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">superType</span> = <span class="string">&quot;Animal&quot;</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name || <span class="string">&quot;动物&quot;</span>;</span><br><span class="line">        <span class="comment">//实例方法</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">sleep</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;正在睡觉!!&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;</span><br><span class="line"><span class="comment">//原型上的函数</span></span><br><span class="line">      <span class="title class_">Animal</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">eat</span> = <span class="keyword">function</span> (<span class="params">food</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;正在吃:&quot;</span> + food);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Dog</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 改变Dog的prototype指向，指向了一个Animal实例，实现了原型继承</span></span><br><span class="line">      <span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Animal</span>();</span><br><span class="line">      <span class="keyword">var</span> doggie = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&quot;wangcai&quot;</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(doggie.<span class="property">superType</span>);</span><br><span class="line">      doggie.<span class="title function_">sleep</span>();</span><br><span class="line">      doggie.<span class="title function_">eat</span>(<span class="string">&quot;狗粮&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，将<code>Animal</code>的实例赋值给了<code>Dog</code>的原型对象，这样就实现了原型的继承，所以<code>Dog</code>的实例可以获取父类<code>Animal</code>中的<code>superType</code>属性，调用父类中的实例方法，原型上的函数。</p>
<p>下面，可以通过一张图来理解一下：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E7%BB%A7%E6%89%BF1.png"></p>
<p>原来的构造函数<code>Dog</code>的<code>prototype</code>指向的是<code>Dog</code>的原型对象，但是现在指向了<code>Animal</code>的实例对象。也就是说构造函数<code>Dog</code>的原型对象为<code>Animal</code>的实例对象。</p>
<p>这样会出现什么样的效果呢？</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E5%8E%9F%E5%9E%8B%E7%BB%A7%E6%89%BF2.png"></p>
<p>注意：上面我们所写的代码还是有一个小的问题的。</p>
<p><code>Dog.prototype.constructor</code>指向了<code>Animal</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span>===<span class="title class_">Animal</span> <span class="comment">// true</span></span><br></pre></td></tr></table></figure>

<p>这里，还是要求<code>Dog.prototype.constructor</code>指向<code>Dog</code></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Animal</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">superType</span> = <span class="string">&quot;Animal&quot;</span>;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">name</span> = name || <span class="string">&quot;动物&quot;</span>;</span><br><span class="line">       <span class="comment">//实例方法</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">sleep</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;正在睡觉!!&quot;</span>);</span><br><span class="line">       &#125;;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Animal</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">eat</span> = <span class="keyword">function</span> (<span class="params">food</span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&quot;正在吃:&quot;</span> + food);</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Dog</span>(<span class="params">name</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="comment">// 改变Dog的prototype指向，指向了一个Animal实例，实现了原型继承</span></span><br><span class="line">     <span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Animal</span>();</span><br><span class="line">     <span class="comment">// 将Dog的构造函数指向自身</span></span><br><span class="line">     <span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Dog</span>;</span><br><span class="line">     <span class="keyword">var</span> doggie = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&quot;wangcai&quot;</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(doggie.<span class="property">superType</span>);</span><br><span class="line">     doggie.<span class="title function_">sleep</span>();</span><br><span class="line">     doggie.<span class="title function_">eat</span>(<span class="string">&quot;狗粮&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>原型继承的优点：</p>
<p>第一：实现起来非常简单</p>
<p>只要设置子类的<code>portotype</code>属性为父类的实例即可。</p>
<p>第二：可以通过子类的实例直接访问父类原型链中的属性和函数。</p>
<p>原型继承的缺点：</p>
<p>第一：我们知道子类的所有实例将共享父类的属性，这样就会导致一个问题：如果父类中的某个属性的值为引用类型，某个子类的实例去修改这个属性的值，就会影响到其它实例的值。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">  <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Studnet</span>;</span><br><span class="line">  <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;]</span></span><br><span class="line">  stu1.<span class="property">emotion</span>.<span class="title function_">push</span>(<span class="string">&quot;玩游戏&quot;</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;, &quot;玩游戏&quot;]</span></span><br><span class="line">  <span class="comment">//创建 stu2对象</span></span><br><span class="line">  <span class="keyword">var</span> stu2 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1002</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(stu2.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;, &quot;玩游戏&quot;]</span></span><br></pre></td></tr></table></figure>

<p>通过上面的代码，我们可以看到<code>stu1</code>对象向数组<code>emotion</code>数组中添加了一项以后，<code>stu2</code>对象也收到了影响。</p>
<p>第二：在创建子类的实例的时候，无法向父类的构造函数中传递参数。</p>
<p>在通过<code>new</code>操作符创建子类的实例的时候，会调用子类的构造函数，而在子类的构造函数中并没有设置与父类的关联操作，所以无法向父类的构造函数中传递参数。</p>
<p>第三：在给子类的原型对象上添加属性或者是方法的时候，一定要放在<code>Student.prototype=new Person</code>语句的后面。</p>
<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">   <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">      &#125;</span><br><span class="line"><span class="comment">//在Studnet.prototype = new Person();代码前给Student的prototype添加study方法。</span></span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;好好学习，天天向上&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Studnet</span>;</span><br><span class="line">      <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>);</span><br><span class="line">      stu1.<span class="title function_">study</span>();</span><br></pre></td></tr></table></figure>

<p>指向上面的代码，会出现<code>stu1.study is not a function</code>的错误。</p>
<p>原因：后面通过<code>Studnet.prototype = new Person();</code>这行代码对<code>Student</code>的原型对象进行了重写，所以导致<code>study</code>方法无效了。</p>
<p>修改后的代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">      <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Studnet</span>;</span><br><span class="line"><span class="comment">//放在了Studnet.prototype=new Person语句的后面</span></span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;好好学习，天天向上&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>);</span><br><span class="line">      stu1.<span class="title function_">study</span>();</span><br></pre></td></tr></table></figure>

<h3 id="构造函数继承"><a href="#构造函数继承" class="headerlink" title="构造函数继承"></a>构造函数继承</h3><p>在子类的构造函数中，通过<code>apply()</code>方法或者是<code>call()</code>方法，调用父类的构造函数，从而实现继承功能。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">      <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">emotion</span>);</span><br></pre></td></tr></table></figure>



<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id</span>) &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">     <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>);</span><br><span class="line">   <span class="keyword">var</span> stu2 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1002</span>);</span><br><span class="line">   stu1.<span class="property">emotion</span>.<span class="title function_">push</span>(<span class="string">&quot;玩游戏&quot;</span>);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;, &quot;玩游戏&quot;]</span></span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(stu2.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;]</span></span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以看到<code>stu1</code>对象向<code>emotion</code>数组中添加数据，并不会影响到<code>stu2</code>对象。</p>
<p><strong>构造函数继承的优点</strong></p>
<p>第一：由于在子类的构造中通过<code>call</code>改变了父类中的<code>this</code>指向，导致了在父类构造函数中定义的属性或者是方法都赋值给了子类，这样生成的每个子类的实例中都具有了这些属性和方法。而且它们之间是互不影响的，及时是引用类型。</p>
<p>第二：创建子类的实例的时候，可以向父类的构造函数中传递参数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//传递age参数   </span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; </span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">      &#125;</span><br><span class="line"><span class="comment">//传递age参数</span></span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">id</span> = id; </span><br><span class="line">         <span class="comment">// 传递age参数</span></span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">20</span>);<span class="comment">//传递年龄</span></span><br><span class="line">      <span class="keyword">var</span> stu2 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1002</span>, <span class="number">21</span>);</span><br><span class="line">      stu1.<span class="property">emotion</span>.<span class="title function_">push</span>(<span class="string">&quot;玩游戏&quot;</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;, &quot;玩游戏&quot;]</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(stu2.<span class="property">emotion</span>); <span class="comment">// [&quot;吃饭&quot;, &quot;睡觉&quot;, &quot;学习&quot;]</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(stu1.<span class="property">age</span>); <span class="comment">// 20</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(stu2.<span class="property">age</span>); <span class="comment">// 21</span></span><br></pre></td></tr></table></figure>

<p><strong>构造函数继承的缺点</strong></p>
<p>第一：子类只能继承父类中实例的属性和方法，无法继承父类原型对象上的属性和方法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="comment">// 原型上的方法</span></span><br><span class="line">   <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;好好学习，天天向上&quot;</span>);</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">     <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">var</span> stu = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">20</span>);</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(stu.<span class="property">age</span>); <span class="comment">// 20</span></span><br><span class="line">   stu.<span class="title function_">study</span>(); <span class="comment">//stu.study is not a function</span></span><br></pre></td></tr></table></figure>

<p>第二：在父类的构造函数中添加一个实例方法，对应的子类也就有了该实例方法，但是问题时，每创建一个子类的实例，都会有一个父类中的实例方法，这样导致的结果就是占用内存比较大。以前我们是定义在<code>prototype</code>原型上来解决这个问题的，但是在构造函数的继承中，又出现了这个。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">  <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号同学要努力学习&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">// 学号</span></span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">var</span> stu = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">20</span>);</span><br><span class="line">      stu.<span class="title function_">study</span>();</span><br><span class="line">      <span class="keyword">var</span> stu1 = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1002</span>, <span class="number">20</span>);</span><br><span class="line">      stu1.<span class="title function_">study</span>();</span><br><span class="line"><span class="comment">//stu对象和stu1对象都单独有一个study方法。</span></span><br></pre></td></tr></table></figure>

<h3 id="拷贝继承"><a href="#拷贝继承" class="headerlink" title="拷贝继承"></a>拷贝继承</h3><p>所谓的拷贝继承指的是先创建父类的实例，然后通过<code>for...in</code>的方式来遍历父类实例中的所有属性和方法，并依次赋值给子类的实例，同时原型上的属性和函数也赋给子类的实例。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号同学要努力学习&quot;</span>);</span><br><span class="line">       &#125;;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">run</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生正在跑步,年龄是:&quot;</span> + <span class="variable language_">this</span>.<span class="property">age</span>);</span><br><span class="line">     &#125;;</span><br><span class="line"></span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(age);</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> person) &#123;</span><br><span class="line">         <span class="keyword">if</span> (person.<span class="title function_">hasOwnProperty</span>(key)) &#123;</span><br><span class="line">           <span class="variable language_">this</span>[key] = person[key];</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>[key] = person[key];</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">// 子类自身的属性</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">id</span> = id;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">21</span>);</span><br><span class="line">     student.<span class="title function_">study</span>();</span><br><span class="line">     student.<span class="title function_">run</span>();</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，创建了父类<code>Person</code>,并且在该类中指定了相应的实例属性和实例方法，同时为其原型对象中也添加了方法。</p>
<p>在<code>Studnet</code>这个子类中，首先会创建父类<code>Person</code>的实例，然后通过<code>for...in</code>来进行遍历，获取父类中的属性和方法，获取以后进行判断，如果<code>person.hasOwnProperty(key)</code>返回值为<code>false</code>，表示获取到的是父类原型对象上的属性和方法，所以也要添加到子类的<code>prototype</code>属性上，成为子类的原生对象上的属性或者是方法。</p>
<p>最后创建子类的实例<code>student</code>,通过子类的实例<code>student</code>,可以访问继承到的属性或者是方法。</p>
<p><strong>拷贝继承的优点</strong></p>
<p>第一：可以实现向父类中的构造方法中传递参数。</p>
<p>第二：能够实现让子类继承父类中的实例属性，实例方法以及原型对象上的属性和方法。</p>
<p><strong>拷贝继承的缺点</strong></p>
<p>父类的所有属性和方法，子类都需要复制拷贝一遍，所以比较消耗内存。</p>
<h3 id="组合继承"><a href="#组合继承" class="headerlink" title="组合继承"></a>组合继承</h3><p>组合继承的核心思想是将构造函数继承与原型继承两种方式组合在一起。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号同学要努力学习&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">run</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生正在跑步,年龄是:&quot;</span> + <span class="variable language_">this</span>.<span class="property">age</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">//子类独有的属性</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">    <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Studnet</span>;</span><br><span class="line">    <span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">21</span>);</span><br><span class="line">    student.<span class="title function_">run</span>();</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;爱好是:&quot;</span> + student.<span class="property">emotion</span>);</span><br></pre></td></tr></table></figure>

<p><strong>组合继承的优点</strong></p>
<p>第一：通过<code>Person.call(this,ge)</code>这个行代码，可以将父类中的实例属性和方法添加到子类<code>Student</code>中，另外通过<code>Studnet.prototype = new Person();</code> 可以将父类的原型对象上的属性和函数绑定到<code>Student</code>的原型对象上。</p>
<p>第二：可以向父类的构造函数中传递参数。</p>
<p> <strong>组合继承的缺点</strong></p>
<p>组合继承的主要缺点是父类的实例属性会绑定两次。</p>
<p>第一次是在子类的构造函数中通过<code>call( )</code>函数调用了一次父类的构造函数，完成实例属性和方法的绑定操作。</p>
<p>第二次是在改写子类<code>prototype</code>属性的时候，我们执行了一次<code>new Person()</code>的操作，这里又将父类的构造函数调用了一次，完成了属性的绑定操作。</p>
<p>所以在整个组合继承的过程中，父类实例的属性和方法会进行两次的绑定操作。当然这里需要你注意的一点是：通过<code>call()</code>函数完成父类中实例属性和方法的绑定的优先级要高于通过改写子类<code>prototype</code>的方式。也就是说第一种方式会覆盖第二种方式：</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">    <span class="comment">//实例方法</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号同学要努力学习&quot;</span>);</span><br><span class="line">       &#125;;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">run</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生正在跑步,年龄是:&quot;</span> + <span class="variable language_">this</span>.<span class="property">age</span>);</span><br><span class="line">     &#125;;</span><br><span class="line">   <span class="comment">// 原型方法</span></span><br><span class="line">     <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生需要好好学习&quot;</span>);</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">       <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">id</span> = id; <span class="comment">//子类独有的属性</span></span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">     <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Student</span>;</span><br><span class="line">     <span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">21</span>);</span><br><span class="line">     student.<span class="title function_">run</span>();</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;爱好是:&quot;</span> + student.<span class="property">emotion</span>);</span><br><span class="line">     student.<span class="title function_">study</span>(); <span class="comment">//调用父类的实例方法student</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，在父类<code>Person</code>的构造函数中定义了实例方法<code>study</code>,同时在其原型对象上也定义了一个<code>study</code>方法。</p>
<p>通过子类的实例调用<code>study</code>方法的时候，调用的是父类的实例方法<code>study</code>.</p>
<h3 id="寄生式组合继承"><a href="#寄生式组合继承" class="headerlink" title="寄生式组合继承"></a>寄生式组合继承</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">   <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">age</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emotion</span> = [<span class="string">&quot;吃饭&quot;</span>, <span class="string">&quot;睡觉&quot;</span>, <span class="string">&quot;学习&quot;</span>]; <span class="comment">// 爱好</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = age;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号同学要努力学习&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">run</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生正在跑步,年龄是:&quot;</span> + <span class="variable language_">this</span>.<span class="property">age</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">study</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">id</span> + <span class="string">&quot;号学生需要好好学习&quot;</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Studnet</span>(<span class="params">id, age</span>) &#123;</span><br><span class="line">        <span class="title class_">Person</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>, age);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">id</span> = id;</span><br><span class="line">      &#125;</span><br><span class="line"><span class="comment">// 定义Super构造函数</span></span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">Super</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line"><span class="comment">//Super.prototype原型对象指向了Person.prototype</span></span><br><span class="line">      <span class="title class_">Super</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"><span class="comment">//Student.prototype原型对象指向了Super的实例，这样就去掉了Person父类的实例属性。</span></span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Super</span>();</span><br><span class="line">      <span class="title class_">Studnet</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">constructor</span> = <span class="title class_">Studnet</span>;</span><br><span class="line">      <span class="keyword">var</span> student = <span class="keyword">new</span> <span class="title class_">Studnet</span>(<span class="number">1001</span>, <span class="number">21</span>);</span><br><span class="line">      student.<span class="title function_">run</span>();</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;爱好是:&quot;</span> + student.<span class="property">emotion</span>);</span><br><span class="line">      student.<span class="title function_">study</span>();</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，创建了一个<code>Super</code>构造函数，让<code>Super.prototype</code>的原型指向了<code>Person.prototype</code>,同时将<code>Super</code>的对象赋值给了<code>Student.prototype</code>，这样就去掉了<code>Person</code>父类的实例属性。</p>
<p>通过寄生式组合继承解决了组合继承的问题。</p>
<p>同时，在以后的应用中，可以使用组合继承，也可以使用寄生式组合继承。</p>
<h2 id="7、模拟jQuery实现"><a href="#7、模拟jQuery实现" class="headerlink" title="7、模拟jQuery实现"></a>7、模拟jQuery实现</h2><p>下面我们通过模拟实现一个简单的<code>jQuery</code>,来巩固原型的应用。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="comment">// 为jQuery起一个别名，模仿jQuery的框架</span></span><br><span class="line">    <span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;&#125;);</span><br><span class="line">    <span class="comment">// 为jQuery原型起一个别名</span></span><br><span class="line">    <span class="comment">//这里没有直接赋值给fn，否则它属于window对象，容易造成全局污染</span></span><br><span class="line">    <span class="comment">//后面要访问jquery的原型，可以直接通过jQuery.fn来实现</span></span><br><span class="line">    jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">      <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>, <span class="comment">//添加原型属性，表示jquery的版本</span></span><br><span class="line">      <span class="comment">//添加原型方法，表示返回jquery对象的长度</span></span><br><span class="line">      <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">    </span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>下面，我们使用<code>jQuery</code>原型中的<code>size</code>方法和<code>version</code>属性。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 为jQuery起一个别名，模仿jQuery的框架</span></span><br><span class="line">   <span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;&#125;);</span><br><span class="line">   <span class="comment">// 为jQuery原型起一个别名</span></span><br><span class="line">   <span class="comment">//这里没有直接赋值给fn，否则它属于window对象，容易造成全局污染</span></span><br><span class="line">   <span class="comment">//后面要访问jquery的原型，可以直接通过jQuery.fn来实现</span></span><br><span class="line">   jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">     <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>, <span class="comment">//添加原型属性，表示jquery的版本</span></span><br><span class="line">     <span class="comment">//添加原型方法，表示返回jquery对象的长度</span></span><br><span class="line">     <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">var</span> jq = <span class="keyword">new</span> $();</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(jq.<span class="property">version</span>); <span class="comment">// 6.1.1</span></span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(jq.<span class="title function_">size</span>()); <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们是创建了一个<code>jquery</code>的实例，然后通过该实例完成了原型属性和方法的调用。</p>
<p>但是在<code>jquery</code>库中，是采用如下的方式进行调用。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">$().<span class="property">version</span>;</span><br><span class="line">$().<span class="title function_">size</span>()</span><br></pre></td></tr></table></figure>

<p>通过以上的两行代码，我们可以看到在<code>jQuery</code>库中，并没有使用<code>new</code>操作符，而是直接使用小括号运算符完成了对<code>jQuery</code>构造函数的调用。然后后面直接访问原型成员。</p>
<p>那应该怎样实现这种操作？</p>
<p>我们想到的就是，在<code>jquery</code>的构造函数中，直接创建<code>jQuery</code>类的实例。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 为jQuery起一个别名，模仿jQuery的框架</span></span><br><span class="line">   <span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="keyword">new</span> <span class="title function_">jQuery</span>();</span><br><span class="line">   &#125;);</span><br><span class="line">   <span class="comment">// 为jQuery原型起一个别名</span></span><br><span class="line">   <span class="comment">//这里没有直接赋值给fn，否则它属于window对象，容易造成全局污染</span></span><br><span class="line">   <span class="comment">//后面要访问jquery的原型，可以直接通过jQuery.fn来实现</span></span><br><span class="line">   jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">     <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>, <span class="comment">//添加原型属性，表示jquery的版本</span></span><br><span class="line">     <span class="comment">//添加原型方法，表示返回jquery对象的长度</span></span><br><span class="line">     <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">   &#125;;</span><br><span class="line">   $().<span class="property">version</span>;</span><br><span class="line">   <span class="comment">//   var jq = new $();</span></span><br><span class="line">   <span class="comment">//   console.log(jq.version); // 6.1.1</span></span><br><span class="line">   <span class="comment">//   console.log(jq.size());</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，给<code>jQuery</code>构造函数直接返回了<code>它的实例</code>，<code>return new jQuery();</code></p>
<p>然后获取原型对象中的<code>size</code>属性的值:<code>$().version</code>.</p>
<p>但是，出现了如下的错误：</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Uncaught RangeError: Maximum call stack size exceeded</span><br></pre></td></tr></table></figure>

<p>以上错误的含义是栈内存溢出。</p>
<p>原因就是：当我们通过<code>$()</code>调用构造函数的时候，内部有执行了<code>new</code>操作，这时，又会重新执行<code>jQuery</code>的构造函数，这样就造成了死循环。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">  </span><br><span class="line"><span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(); <span class="comment">//调用原型中的`init方法`</span></span><br><span class="line">&#125;);</span><br><span class="line">     </span><br><span class="line">jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">init</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>; <span class="comment">//返回jquery的原型对象</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>,        </span><br><span class="line">  <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="property">version</span>);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，在<code>jQuery</code>的构造方法中，调用的是原型中的<code>init</code>方法，在该方法中，返回了<code>jquery</code>的原型对象。</p>
<p>最后进行输出:<code>cosnole.log($().version)</code></p>
<p>但是，以上的处理还是隐藏一个问题，具体看如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(); </span><br><span class="line">     &#125;);</span><br><span class="line">     jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">       <span class="attr">init</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">0</span>; <span class="comment">//原型属性length</span></span><br><span class="line">         <span class="variable language_">this</span>.<span class="property">_size</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123; <span class="comment">//原型方法</span></span><br><span class="line">           <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">         &#125;;</span><br><span class="line">         <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>,</span><br><span class="line">       <span class="attr">length</span>: <span class="number">1</span>, <span class="comment">// 原型属性</span></span><br><span class="line">       <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="property">version</span>);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">_size</span>()); <span class="comment">// 0</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">size</span>()); <span class="comment">// 0</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，在<code>init</code>这个原型方法中添加了<code>lenght</code>属性与<code>_size</code>方法，在该方法中打印<code>length</code>的值。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(); <span class="comment">//调用原型中的`init方法`</span></span><br><span class="line">     &#125;);</span><br></pre></td></tr></table></figure>

<p>在<code>jQuery</code>的构造函数中，通过<code>new</code>操作符创建了一个实例对象，这样<code>init()</code>方法中的<code>this</code>指向的就是<code>init</code>方法的实例，而不是<code>jQuery.prototype</code>这个原型对象了。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="property">version</span>); <span class="comment">// 返回undefined</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">_size</span>()); <span class="comment">// 0</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">size</span>()); <span class="comment">// 抛出异常：Uncaught TypeError: $(...).size is not a function</span></span><br></pre></td></tr></table></figure>



<p>下面，我们来看一下怎样解决现在面临的问题。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(); <span class="comment">//调用原型中的`init方法`</span></span><br><span class="line">    &#125;);</span><br><span class="line">    jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">      <span class="attr">init</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_size</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">version</span>: <span class="string">&quot;6.1.1&quot;</span>,</span><br><span class="line">      <span class="attr">length</span>: <span class="number">1</span>,</span><br><span class="line">      <span class="attr">size</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">length</span>;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"><span class="comment">// 将`jQuery`的原型对象覆盖掉init的原型对象。</span></span><br><span class="line">    jQuery.<span class="property">fn</span>.<span class="property">init</span>.<span class="property"><span class="keyword">prototype</span></span> = jQuery.<span class="property">fn</span>;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="property">version</span>); <span class="comment">//6.1.1</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">_size</span>()); <span class="comment">// 0</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="title function_">size</span>()); <span class="comment">// 0</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们添加了一行代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery.<span class="property">fn</span>.<span class="property">init</span>.<span class="property"><span class="keyword">prototype</span></span> = jQuery.<span class="property">fn</span>;</span><br></pre></td></tr></table></figure>



<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>($().<span class="property">version</span>); </span><br></pre></td></tr></table></figure>



<p><strong>下面，要实现的是选择器功能</strong></p>
<p><code>jQuery</code>构造函数包括两个参数，分别是<code>selector</code>和<code>context</code>,<code>selector</code>表示的是选择器，<code>context</code>表示匹配的上下文，也就是可选择的访问，一般表示的是一个<code>DOM</code>元素。这里我们只考虑标签选择器。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="comment">// 给构造函数传递selector,context两个参数</span></span><br><span class="line">      <span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params">selector, context</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(selector, context); <span class="comment">//调用原型中的`init方法`</span></span><br><span class="line">      &#125;);</span><br><span class="line">      jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">        <span class="attr">init</span>: <span class="keyword">function</span> (<span class="params">selector, context</span>) &#123;</span><br><span class="line">          selector = selector || <span class="variable language_">document</span>; <span class="comment">//初始化选择器，默认值为document</span></span><br><span class="line">          context = context || <span class="variable language_">document</span>; <span class="comment">// 初始化上下文对象，默认值为document</span></span><br><span class="line">          <span class="keyword">if</span> (selector.<span class="property">nodeType</span>) &#123;</span><br><span class="line">            <span class="comment">// 如果是DOM元素</span></span><br><span class="line">            <span class="comment">// 把该DOM元素赋值给实例对象</span></span><br><span class="line">            <span class="variable language_">this</span>[<span class="number">0</span>] = selector;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">1</span>; <span class="comment">//表示包含了1个元素</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">context</span> = selector; <span class="comment">//重新设置上下文对象</span></span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>; <span class="comment">//返回当前实例</span></span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">if</span> (<span class="keyword">typeof</span> selector === <span class="string">&quot;string&quot;</span>) &#123;</span><br><span class="line">            <span class="comment">//如果选择器是一个字符串</span></span><br><span class="line">            <span class="keyword">var</span> e = context.<span class="title function_">getElementsByTagName</span>(selector); <span class="comment">// 获取指定名称的元素</span></span><br><span class="line">            <span class="comment">//通过for循环将所有元素存储到当前的实例中</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; e.<span class="property">length</span>; i++) &#123;</span><br><span class="line">              <span class="variable language_">this</span>[i] = e[i];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">length</span> = e.<span class="property">length</span>; <span class="comment">//存储元素的个数</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">context</span> = context; <span class="comment">//保存上下文对象</span></span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>; <span class="comment">//返回当前的实例</span></span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">0</span>;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">context</span> = context;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="comment">//   this.length = 0;</span></span><br><span class="line">          <span class="comment">//   console.log(&quot;init==&quot;, this);</span></span><br><span class="line">          <span class="comment">//   this._size = function () &#123;</span></span><br><span class="line">          <span class="comment">//     return this.length;</span></span><br><span class="line">          <span class="comment">//   &#125;;</span></span><br><span class="line">          <span class="comment">//   return this;</span></span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        <span class="comment">// version: &quot;6.1.1&quot;,</span></span><br><span class="line">        <span class="comment">// length: 1,</span></span><br><span class="line">        <span class="comment">// size: function () &#123;</span></span><br><span class="line">        <span class="comment">//   return this.length;</span></span><br><span class="line">        <span class="comment">// &#125;,</span></span><br><span class="line">      &#125;;</span><br><span class="line">      jQuery.<span class="property">fn</span>.<span class="property">init</span>.<span class="property"><span class="keyword">prototype</span></span> = jQuery.<span class="property">fn</span>;</span><br><span class="line">      <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>($(<span class="string">&quot;div&quot;</span>).<span class="property">length</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="comment">//   console.log($().version);</span></span><br><span class="line">      <span class="comment">//   console.log($()._size()); // 0</span></span><br><span class="line">      <span class="comment">//   console.log($().size()); // 0</span></span><br><span class="line">      <span class="comment">//   var jq = new $();</span></span><br><span class="line">      <span class="comment">//   console.log(jq.version); // 6.1.1</span></span><br><span class="line">      <span class="comment">//   console.log(jq.size());</span></span><br><span class="line">    &lt;/script&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">  &lt;/body&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，当页面加载完以后，这时会触发<code>onload</code>事件，在该事件对应的处理函数中，通过<code>$(&quot;div&quot;)</code>,传递的是字符串，</p>
<p><code>selector</code>参数表示的就是<code>div</code>这个字符串，这里没有传递<code>context</code>参数，表示的就是<code>document</code>对象。</p>
<p>最后打印元素的个数。</p>
<p>在使用<code>jQuery</code>库的时候，我们经常可以看到如下的操作：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">$(<span class="string">&#x27;div&#x27;</span>).<span class="title function_">html</span>()</span><br></pre></td></tr></table></figure>

<p>以上代码的含义就是直接在<code>jQuery</code>对象上调用<code>html( )</code>方法来操作<code>jQuery</code>包含所有的<code>DOM</code>元素。</p>
<p><code>html()</code>方法的实现如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;!<span class="variable constant_">DOCTYPE</span> html&gt;</span><br><span class="line">&lt;html lang=&quot;en&quot;&gt;</span><br><span class="line">  &lt;head&gt;</span><br><span class="line">    &lt;meta charset=&quot;UTF-8&quot; /&gt;</span><br><span class="line">    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;</span><br><span class="line">    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;</span><br><span class="line">    &lt;title&gt;Document&lt;/title&gt;</span><br><span class="line">  &lt;/head&gt;</span><br><span class="line">  &lt;body&gt;</span><br><span class="line">    &lt;script&gt;</span><br><span class="line">      // 给构造函数传递selector,context两个参数</span><br><span class="line">      var $ = (jQuery = function (selector, context) &#123;</span><br><span class="line">        return new jQuery.fn.init(selector, context); //调用原型中的`init方法`</span><br><span class="line">      &#125;);</span><br><span class="line">      jQuery.fn = jQuery.prototype = &#123;</span><br><span class="line">        init: function (selector, context) &#123;</span><br><span class="line">          selector = selector || document; //初始化选择器，默认值为document</span><br><span class="line">          context = context || document; // 初始化上下文对象，默认值为document</span><br><span class="line">          if (selector.nodeType) &#123;</span><br><span class="line">            // 如果是DOM元素</span><br><span class="line">            // 把该DOM元素赋值给实例对象</span><br><span class="line">            this[0] = selector;</span><br><span class="line">            this.length = 1; //表示包含了1个元素</span><br><span class="line">            this.context = selector; //重新设置上下文对象</span><br><span class="line">            return this; //返回当前实例</span><br><span class="line">          &#125;</span><br><span class="line">          if (typeof selector === &quot;string&quot;) &#123;</span><br><span class="line">            //如果选择器是一个字符串</span><br><span class="line">            var e = context.getElementsByTagName(selector); // 获取指定名称的元素</span><br><span class="line">            //通过for循环将所有元素存储到当前的实例中</span><br><span class="line">            for (var i = 0; i &lt; e.length; i++) &#123;</span><br><span class="line">              this[i] = e[i];</span><br><span class="line">            &#125;</span><br><span class="line">            this.length = e.length; //存储元素的个数</span><br><span class="line">            this.context = context; //保存上下文对象</span><br><span class="line">            return this; //返回当前的实例</span><br><span class="line">          &#125; else &#123;</span><br><span class="line">            this.length = 0;</span><br><span class="line">            this.context = context;</span><br><span class="line">            return this;</span><br><span class="line">          &#125;</span><br><span class="line">          //   this.length = 0;</span><br><span class="line">          //   console.log(&quot;init==&quot;, this);</span><br><span class="line">          //   this._size = function () &#123;</span><br><span class="line">          //     return this.length;</span><br><span class="line">          //   &#125;;</span><br><span class="line">          //   return this;</span><br><span class="line">        &#125;,</span><br><span class="line">        html: function (val) &#123;</span><br><span class="line">          jQuery.each(</span><br><span class="line">            this,</span><br><span class="line">            function (val) &#123;</span><br><span class="line">              this.innerHTML = val;</span><br><span class="line">            &#125;,</span><br><span class="line">            val</span><br><span class="line">          );</span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">        // version: &quot;6.1.1&quot;,</span><br><span class="line">        // length: 1,</span><br><span class="line">        // size: function () &#123;</span><br><span class="line">        //   return this.length;</span><br><span class="line">        // &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line">      jQuery.fn.init.prototype = jQuery.fn;</span><br><span class="line"></span><br><span class="line">      //提供each扩展方法</span><br><span class="line">      jQuery.each = function (object, callback, args) &#123;</span><br><span class="line">        //通过for循环的方式来遍历jQuery对象中的每个DOM元素。</span><br><span class="line">        for (var i = 0; i &lt; object.length; i++) &#123;</span><br><span class="line">          // 在每个DOM元素上调用回调函数</span><br><span class="line">          callback.call(object[i], args);</span><br><span class="line">        &#125;</span><br><span class="line">        return object; //返回jQuery对象。</span><br><span class="line">      &#125;;</span><br><span class="line">      window.onload = function () &#123;</span><br><span class="line">        // console.log($(&quot;div&quot;).length);</span><br><span class="line">        $(&quot;div&quot;).html(&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;);</span><br><span class="line">      &#125;;</span><br><span class="line">      //   console.log($().version);</span><br><span class="line">      //   console.log($()._size()); // 0</span><br><span class="line">      //   console.log($().size()); // 0</span><br><span class="line">      //   var jq = new $();</span><br><span class="line">      //   console.log(jq.version); // 6.1.1</span><br><span class="line">      //   console.log(jq.size());</span><br><span class="line">    &lt;/script&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">  &lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，首先添加了<code>jQuery.each</code>方法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//提供each扩展方法</span></span><br><span class="line">  jQuery.<span class="property">each</span> = <span class="keyword">function</span> (<span class="params">object, callback, args</span>) &#123;</span><br><span class="line">    <span class="comment">//通过for循环的方式来遍历jQuery对象中的每个DOM元素。</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; object.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="comment">// 在每个DOM元素上调用回调函数</span></span><br><span class="line">        <span class="comment">//这里的让回调函数中的this指向了dom元素。</span></span><br><span class="line">      callback.<span class="title function_">call</span>(object[i], args);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> object; <span class="comment">//返回jQuery对象。</span></span><br><span class="line">  &#125;;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，通过<code>for</code>循环遍历<code>jQuery</code>对象中的每个<code>DOM</code>元素。然后执行回调函数<code>callback</code></p>
<p>在<code>jQuery</code>的原型对象上，添加<code>html</code>方法</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="attr">html</span>: <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">        jQuery.<span class="title function_">each</span>(</span><br><span class="line">          <span class="variable language_">this</span>, <span class="comment">//表示jQuery原型对象</span></span><br><span class="line">          <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">              <span class="comment">//this表示的是dom元素，这里是div元素</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">innerHTML</span> = val;</span><br><span class="line">          &#125;,</span><br><span class="line">          val <span class="comment">//表示传递过来的`&lt;h2&gt;hello&lt;h2&gt;`</span></span><br><span class="line">        );</span><br><span class="line">      &#125;,</span><br></pre></td></tr></table></figure>

<p>在<code>html</code>方法中完成对<code>jQuery.each</code>方法的调用。</p>
<p><code>window.onload</code>的方法修改成如下的形式：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// console.log($(&quot;div&quot;).length);</span></span><br><span class="line">    $(<span class="string">&quot;div&quot;</span>).<span class="title function_">html</span>(<span class="string">&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;</span>);</span><br><span class="line">  &#125;;</span><br></pre></td></tr></table></figure>

<h2 id="下面我们实现jQuery的扩展功能"><a href="#下面我们实现jQuery的扩展功能" class="headerlink" title="**下面我们实现jQuery的扩展功能"></a>**下面我们实现<code>jQuery</code>的扩展功能</h2><p>jQuery 提供了良好的扩展接口，方便用户自定义 jQuery 方法。根据设计习惯，如果为 jQuery 或者 jQuery.prototype 新增方法时，我们可以直接通过点语法来实现，例如上面我们扩展的<code>html</code>方法，或者在 jQuery.prototype 对象结构内增加。但是，如果分析 jQuery 源码，会发现它是通过 extend() 函数来实现功能扩展的。</p>
<p>通过<code>extend()</code>方法来实现扩展的好处是：方便用户快速的扩展<code>jQuery</code>功能，但不会破坏<code>jQuery</code>框架的结构。如果直接在<code>jQuery</code>源码中添加方法，这样就破坏了<code>Jquery</code>框架的结构，不方便后期的代码维护。</p>
<p>如果后期不需要某个功能，可以直接使用<code>Jquery</code>提供的方法删除，而不需要从源码中在对该功能进行删除。</p>
<p>extend() 函数的功能很简单，它只是把指定对象的方法复制给<code> jQuery</code> 对象或者 <code>jQuery.prototype</code>。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">// 给构造函数传递selector,context两个参数</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> $ = (jQuery = <span class="keyword">function</span> (<span class="params">selector, context</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span> <span class="keyword">new</span> jQuery.<span class="property">fn</span>.<span class="title function_">init</span>(selector, context); <span class="comment">//调用原型中的`init方法`</span></span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      jQuery.<span class="property">fn</span> = jQuery.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">init</span>: <span class="keyword">function</span> (<span class="params">selector, context</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          selector = selector || <span class="variable language_">document</span>; <span class="comment">//初始化选择器，默认值为document</span></span></span><br><span class="line"><span class="language-javascript">          context = context || <span class="variable language_">document</span>; <span class="comment">// 初始化上下文对象，默认值为document</span></span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">if</span> (selector.<span class="property">nodeType</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 如果是DOM元素</span></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 把该DOM元素赋值给实例对象</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>[<span class="number">0</span>] = selector;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">1</span>; <span class="comment">//表示包含了1个元素</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">context</span> = selector; <span class="comment">//重新设置上下文对象</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span> <span class="variable language_">this</span>; <span class="comment">//返回当前实例</span></span></span><br><span class="line"><span class="language-javascript">          &#125;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">if</span> (<span class="keyword">typeof</span> selector === <span class="string">&quot;string&quot;</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//如果选择器是一个字符串</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> e = context.<span class="title function_">getElementsByTagName</span>(selector); <span class="comment">// 获取指定名称的元素</span></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//通过for循环将所有元素存储到当前的实例中</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; e.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="variable language_">this</span>[i] = e[i];</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">length</span> = e.<span class="property">length</span>; <span class="comment">//存储元素的个数</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">context</span> = context; <span class="comment">//保存上下文对象</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span> <span class="variable language_">this</span>; <span class="comment">//返回当前的实例</span></span></span><br><span class="line"><span class="language-javascript">          &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">length</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">context</span> = context;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span></span><br><span class="line"><span class="language-javascript">          &#125;</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//   this.length = 0;</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//   console.log(&quot;init==&quot;, this);</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//   this._size = function () &#123;</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//     return this.length;</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//   &#125;;</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//   return this;</span></span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// html: function (val) &#123;</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//   jQuery.each(</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//     this,</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//     function (val) &#123;</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//       this.innerHTML = val;</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//     &#125;,</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//     val</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//   );</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// &#125;,</span></span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// version: &quot;6.1.1&quot;,</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// length: 1,</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// size: function () &#123;</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//   return this.length;</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// &#125;,</span></span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      jQuery.<span class="property">fn</span>.<span class="property">init</span>.<span class="property"><span class="keyword">prototype</span></span> = jQuery.<span class="property">fn</span>;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//提供each扩展方法</span></span></span><br><span class="line"><span class="language-javascript">      jQuery.<span class="property">each</span> = <span class="keyword">function</span> (<span class="params">object, callback, args</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//通过for循环的方式来遍历jQuery对象中的每个DOM元素。</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; object.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// 在每个DOM元素上调用回调函数</span></span></span><br><span class="line"><span class="language-javascript">          callback.<span class="title function_">call</span>(object[i], args);</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span> object; <span class="comment">//返回jQuery对象。</span></span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      jQuery.<span class="property">extend</span> = jQuery.<span class="property">fn</span>.<span class="property">extend</span> = <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">for</span> (<span class="keyword">var</span> prop <span class="keyword">in</span> obj) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">this</span>[prop] = obj[prop];</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      jQuery.<span class="property">fn</span>.<span class="title function_">extend</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">html</span>: <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          jQuery.<span class="title function_">each</span>(</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="variable language_">this</span>.<span class="property">innerHTML</span> = val;</span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            val</span></span><br><span class="line"><span class="language-javascript">          );</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// console.log($(&quot;div&quot;).length);</span></span></span><br><span class="line"><span class="language-javascript">        $(<span class="string">&quot;div&quot;</span>).<span class="title function_">html</span>(<span class="string">&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   console.log($().version);</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   console.log($()._size()); // 0</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   console.log($().size()); // 0</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   var jq = new $();</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   console.log(jq.version); // 6.1.1</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   console.log(jq.size());</span></span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们为<code>jQuery</code>的原型对象添加了<code>extend</code>方法</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery.<span class="property">extend</span> = jQuery.<span class="property">fn</span>.<span class="property">extend</span> = <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">   <span class="keyword">for</span> (<span class="keyword">var</span> prop <span class="keyword">in</span> obj) &#123;</span><br><span class="line">     <span class="variable language_">this</span>[prop] = obj[prop];</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line"> &#125;;</span><br></pre></td></tr></table></figure>

<p>把<code>obj</code>对象中的属性添加到<code>jQuery</code>原型对象上。</p>
<p>下面调用<code>extend</code>方法，同时设置<code>html</code>属性</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery.<span class="property">fn</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">      <span class="attr">html</span>: <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">        jQuery.<span class="title function_">each</span>(</span><br><span class="line">          <span class="variable language_">this</span>,</span><br><span class="line">          <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">innerHTML</span> = val;</span><br><span class="line">          &#125;,</span><br><span class="line">          val</span><br><span class="line">        );</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure>

<p>这样<code>jQuery</code>原型对象上就有了<code>html</code>方法。</p>
<p>而把原来的<code>html</code>方法的代码注释掉。</p>
<p>刷新浏览器，查看对应的效果。</p>
<p><strong>参数传递</strong></p>
<p>我们在使用<code>jquery</code>的方法的时候，需要进行参数的传递，而且一般都要求传递的参数都是对象。</p>
<p>使用对象作为参数进行传递的好处，就是方便参数的管理，例如参数个数不受限制。</p>
<p>如果使用对象作为参数进行传递，需要解决的问题：如何解决并提取参数，如何处理默认值等问题。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;!<span class="variable constant_">DOCTYPE</span> html&gt;</span><br><span class="line">&lt;html lang=&quot;en&quot;&gt;</span><br><span class="line">  &lt;head&gt;</span><br><span class="line">    &lt;meta charset=&quot;UTF-8&quot; /&gt;</span><br><span class="line">    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;</span><br><span class="line">    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;</span><br><span class="line">    &lt;title&gt;Document&lt;/title&gt;</span><br><span class="line">  &lt;/head&gt;</span><br><span class="line">  &lt;body&gt;</span><br><span class="line">    &lt;script&gt;</span><br><span class="line">      // 给构造函数传递selector,context两个参数</span><br><span class="line">      var $ = (jQuery = function (selector, context) &#123;</span><br><span class="line">        return new jQuery.fn.init(selector, context); //调用原型中的`init方法`</span><br><span class="line">      &#125;);</span><br><span class="line">      jQuery.fn = jQuery.prototype = &#123;</span><br><span class="line">        init: function (selector, context) &#123;</span><br><span class="line">          selector = selector || document; //初始化选择器，默认值为document</span><br><span class="line">          context = context || document; // 初始化上下文对象，默认值为document</span><br><span class="line">          if (selector.nodeType) &#123;</span><br><span class="line">            // 如果是DOM元素</span><br><span class="line">            // 把该DOM元素赋值给实例对象</span><br><span class="line">            this[0] = selector;</span><br><span class="line">            this.length = 1; //表示包含了1个元素</span><br><span class="line">            this.context = selector; //重新设置上下文对象</span><br><span class="line">            return this; //返回当前实例</span><br><span class="line">          &#125;</span><br><span class="line">          if (typeof selector === &quot;string&quot;) &#123;</span><br><span class="line">            //如果选择器是一个字符串</span><br><span class="line">            var e = context.getElementsByTagName(selector); // 获取指定名称的元素</span><br><span class="line">            //通过for循环将所有元素存储到当前的实例中</span><br><span class="line">            for (var i = 0; i &lt; e.length; i++) &#123;</span><br><span class="line">              this[i] = e[i];</span><br><span class="line">            &#125;</span><br><span class="line">            this.length = e.length; //存储元素的个数</span><br><span class="line">            this.context = context; //保存上下文对象</span><br><span class="line">            return this; //返回当前的实例</span><br><span class="line">          &#125; else &#123;</span><br><span class="line">            this.length = 0;</span><br><span class="line">            this.context = context;</span><br><span class="line">            return this;</span><br><span class="line">          &#125;</span><br><span class="line">          //   this.length = 0;</span><br><span class="line">          //   console.log(&quot;init==&quot;, this);</span><br><span class="line">          //   this._size = function () &#123;</span><br><span class="line">          //     return this.length;</span><br><span class="line">          //   &#125;;</span><br><span class="line">          //   return this;</span><br><span class="line">        &#125;,</span><br><span class="line">        // html: function (val) &#123;</span><br><span class="line">        //   jQuery.each(</span><br><span class="line">        //     this,</span><br><span class="line">        //     function (val) &#123;</span><br><span class="line">        //       this.innerHTML = val;</span><br><span class="line">        //     &#125;,</span><br><span class="line">        //     val</span><br><span class="line">        //   );</span><br><span class="line">        // &#125;,</span><br><span class="line"></span><br><span class="line">        // version: &quot;6.1.1&quot;,</span><br><span class="line">        // length: 1,</span><br><span class="line">        // size: function () &#123;</span><br><span class="line">        //   return this.length;</span><br><span class="line">        // &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line">      jQuery.fn.init.prototype = jQuery.fn;</span><br><span class="line"></span><br><span class="line">      //提供each扩展方法</span><br><span class="line">      jQuery.each = function (object, callback, args) &#123;</span><br><span class="line">        console.log(&quot;args=&quot;, args);</span><br><span class="line">        //通过for循环的方式来遍历jQuery对象中的每个DOM元素。</span><br><span class="line">        for (var i = 0; i &lt; object.length; i++) &#123;</span><br><span class="line">          // 在每个DOM元素上调用回调函数</span><br><span class="line">          callback.call(object[i], args);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        return object; //返回jQuery对象。</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      // jQuery.extend = jQuery.fn.extend = function (obj) &#123;</span><br><span class="line">      //   for (var prop in obj) &#123;</span><br><span class="line">      //     this[prop] = obj[prop];</span><br><span class="line">      //   &#125;</span><br><span class="line">      //   return this;</span><br><span class="line">      // &#125;;</span><br><span class="line">      jQuery.extend = jQuery.fn.extend = function () &#123;</span><br><span class="line">        var destination = arguments[0],</span><br><span class="line">          source = arguments[1];</span><br><span class="line">        //如果存在两个参数，并且都是对象</span><br><span class="line">        if (typeof destination === &quot;object&quot; &amp;&amp; typeof source === &quot;object&quot;) &#123;</span><br><span class="line">          //把第二个对象合并到第一个参数对象中，并返回合并后的对象</span><br><span class="line">          for (var property in source) &#123;</span><br><span class="line">            destination[property] = source[property];</span><br><span class="line">          &#125;</span><br><span class="line">          return destination;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          for (var prop in destination) &#123;</span><br><span class="line">            this[prop] = destination[prop];</span><br><span class="line">          &#125;</span><br><span class="line">          return this;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;;</span><br><span class="line">      jQuery.fn.extend(&#123;</span><br><span class="line">        html: function (val) &#123;</span><br><span class="line">          jQuery.each(</span><br><span class="line">            this,</span><br><span class="line">            function (val) &#123;</span><br><span class="line">              this.innerHTML = val;</span><br><span class="line">            &#125;,</span><br><span class="line">            val</span><br><span class="line">          );</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      jQuery.fn.extend(&#123;</span><br><span class="line">        fontStyle: function (obj) &#123;</span><br><span class="line">          var defaults = &#123;</span><br><span class="line">            color: &quot;#ccc&quot;,</span><br><span class="line">            size: &quot;16px&quot;,</span><br><span class="line">          &#125;;</span><br><span class="line">          //如果有参数，会覆盖掉默认的参数</span><br><span class="line">          defaults = jQuery.extend(defaults, obj || &#123;&#125;);</span><br><span class="line">          //为每个DOM元素执设置样式.</span><br><span class="line">          jQuery.each(this, function () &#123;</span><br><span class="line">            this.style.color = defaults.color;</span><br><span class="line">            this.style.fontSize = defaults.size;</span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      window.onload = function () &#123;</span><br><span class="line">        // console.log($(&quot;div&quot;).length);</span><br><span class="line">        $(&quot;div&quot;).html(&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;);</span><br><span class="line">        $(&quot;p&quot;).fontStyle(&#123;</span><br><span class="line">          color: &quot;red&quot;,</span><br><span class="line">          size: &quot;30px&quot;,</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;;</span><br><span class="line">      //   console.log($().version);</span><br><span class="line">      //   console.log($()._size()); // 0</span><br><span class="line">      //   console.log($().size()); // 0</span><br><span class="line">      //   var jq = new $();</span><br><span class="line">      //   console.log(jq.version); // 6.1.1</span><br><span class="line">      //   console.log(jq.size());</span><br><span class="line">    &lt;/script&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">    &lt;p&gt;学习前端&lt;/p&gt;</span><br><span class="line">    &lt;p&gt;学习前端&lt;/p&gt;</span><br><span class="line">  &lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，重新改造<code>extend</code>方法。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery.<span class="property">extend</span> = jQuery.<span class="property">fn</span>.<span class="property">extend</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="keyword">var</span> destination = <span class="variable language_">arguments</span>[<span class="number">0</span>],</span><br><span class="line">     source = <span class="variable language_">arguments</span>[<span class="number">1</span>];</span><br><span class="line">   <span class="comment">//如果存在两个参数，并且都是对象</span></span><br><span class="line">   <span class="keyword">if</span> (<span class="keyword">typeof</span> destination === <span class="string">&quot;object&quot;</span> &amp;&amp; <span class="keyword">typeof</span> source === <span class="string">&quot;object&quot;</span>) &#123;</span><br><span class="line">     <span class="comment">//把第二个对象合并到第一个参数对象中，并返回合并后的对象</span></span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">var</span> property <span class="keyword">in</span> source) &#123;</span><br><span class="line">       destination[property] = source[property];</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">return</span> destination;</span><br><span class="line">   &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">var</span> prop <span class="keyword">in</span> destination) &#123;</span><br><span class="line">       <span class="variable language_">this</span>[prop] = destination[prop];</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">   &#125;</span><br><span class="line"> &#125;;</span><br></pre></td></tr></table></figure>

<p>在<code>extend</code>方法中，首先获取两个参数，然后判断这两个参数是否都是对象，如果都是对象，把第二个参数对象合并到第一个参数对象中，并返回合并后的对象。</p>
<p>否则，将第一个参数对象复制到<code>jquery</code>的原型对象上。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery.<span class="property">fn</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">   <span class="attr">fontStyle</span>: <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> defaults = &#123;</span><br><span class="line">       <span class="attr">color</span>: <span class="string">&quot;#ccc&quot;</span>,</span><br><span class="line">       <span class="attr">size</span>: <span class="string">&quot;16px&quot;</span>,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="comment">//如果有参数，会覆盖掉默认的参数</span></span><br><span class="line">     defaults = jQuery.<span class="title function_">extend</span>(defaults, obj || &#123;&#125;);</span><br><span class="line">       <span class="comment">// console.log(&quot;this==&quot;, this);//init &#123;0: p, 1: p, length: 2, context: document&#125;</span></span><br><span class="line">     <span class="comment">//为每个DOM元素执设置样式.</span></span><br><span class="line">     jQuery.<span class="title function_">each</span>(<span class="variable language_">this</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="comment">//这里的this表示的是p标签，因为在each方法内部通过call改变了this指向，让this指向了每个遍历得到的p元素</span></span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">style</span>.<span class="property">color</span> = defaults.<span class="property">color</span>;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">style</span>.<span class="property">fontSize</span> = defaults.<span class="property">size</span>;</span><br><span class="line">     &#125;);</span><br><span class="line">   &#125;,</span><br><span class="line"> &#125;);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中， 调用了<code>extend</code>方法，然后传递了<code>fontStyle</code>,这个<code>fontStyle</code>可以用来设置文本的颜色与字体大小。</p>
<p>当我们第一次调用<code>extend</code>方法的时候，只是传递了<code>fontStyle</code>这个对象，这时，会将该对象添加到<code>jQuery</code>原型对象上。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">   <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="comment">// console.log($(&quot;div&quot;).length);</span></span><br><span class="line">       $(<span class="string">&quot;div&quot;</span>).<span class="title function_">html</span>(<span class="string">&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;</span>);</span><br><span class="line">       $(<span class="string">&quot;p&quot;</span>).<span class="title function_">fontStyle</span>(&#123;</span><br><span class="line">         <span class="attr">color</span>: <span class="string">&quot;red&quot;</span>,</span><br><span class="line">         <span class="attr">size</span>: <span class="string">&quot;30px&quot;</span>,</span><br><span class="line">       &#125;);</span><br><span class="line">     &#125;;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span>学习前端<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span>学习前端<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<p>在<code>onload</code>事件中，调用<code>fontStyle</code>方法，并且传递了一个对象，这时在<code>fontStyle</code>方法的内部，首先会创建一个<code>defaults</code>默认的对象，然后再次调用<code>extend</code>方法，将传递的对象合并到默认对象上，当然完成了值的覆盖。</p>
<p>下面调用<code>each</code>方法，在<code>each</code>方法中遍历每个元素，执行回调函数，并且改变<code>this</code>的指向。</p>
<p><strong>封装成独立的命名空间</strong></p>
<p>以上已经实现了一个简单的<code>jQuery</code>库，</p>
<p>但是这里还有一个问题，需要解决：当编写了大量的<code>javascript</code>代码以后，引入该<code>jquery</code>库就很容易出现代码冲突的问题，所以这里需要将<code>jquery</code>库的代码与其他的<code>javascript</code>代码进行隔离，这里使用闭包。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;!<span class="variable constant_">DOCTYPE</span> html&gt;</span><br><span class="line">&lt;html lang=&quot;en&quot;&gt;</span><br><span class="line">  &lt;head&gt;</span><br><span class="line">    &lt;meta charset=&quot;UTF-8&quot; /&gt;</span><br><span class="line">    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;</span><br><span class="line">    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;</span><br><span class="line">    &lt;title&gt;Document&lt;/title&gt;</span><br><span class="line">  &lt;/head&gt;</span><br><span class="line">  &lt;body&gt;</span><br><span class="line">    &lt;script&gt;</span><br><span class="line">      (function (window) &#123;</span><br><span class="line">        // 给构造函数传递selector,context两个参数</span><br><span class="line">        var $ = (jQuery = function (selector, context) &#123;</span><br><span class="line">          return new jQuery.fn.init(selector, context); //调用原型中的`init方法`</span><br><span class="line">        &#125;);</span><br><span class="line">        jQuery.fn = jQuery.prototype = &#123;</span><br><span class="line">          init: function (selector, context) &#123;</span><br><span class="line">            selector = selector || document; //初始化选择器，默认值为document</span><br><span class="line">            context = context || document; // 初始化上下文对象，默认值为document</span><br><span class="line">            if (selector.nodeType) &#123;</span><br><span class="line">              // 如果是DOM元素</span><br><span class="line">              // 把该DOM元素赋值给实例对象</span><br><span class="line">              this[0] = selector;</span><br><span class="line">              this.length = 1; //表示包含了1个元素</span><br><span class="line">              this.context = selector; //重新设置上下文对象</span><br><span class="line">              return this; //返回当前实例</span><br><span class="line">            &#125;</span><br><span class="line">            if (typeof selector === &quot;string&quot;) &#123;</span><br><span class="line">              //如果选择器是一个字符串</span><br><span class="line">              var e = context.getElementsByTagName(selector); // 获取指定名称的元素</span><br><span class="line">              //通过for循环将所有元素存储到当前的实例中</span><br><span class="line">              for (var i = 0; i &lt; e.length; i++) &#123;</span><br><span class="line">                this[i] = e[i];</span><br><span class="line">              &#125;</span><br><span class="line">              this.length = e.length; //存储元素的个数</span><br><span class="line">              this.context = context; //保存上下文对象</span><br><span class="line">              return this; //返回当前的实例</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">              this.length = 0;</span><br><span class="line">              this.context = context;</span><br><span class="line">              return this;</span><br><span class="line">            &#125;</span><br><span class="line">            //   this.length = 0;</span><br><span class="line">            //   console.log(&quot;init==&quot;, this);</span><br><span class="line">            //   this._size = function () &#123;</span><br><span class="line">            //     return this.length;</span><br><span class="line">            //   &#125;;</span><br><span class="line">            //   return this;</span><br><span class="line">          &#125;,</span><br><span class="line">          // html: function (val) &#123;</span><br><span class="line">          //   jQuery.each(</span><br><span class="line">          //     this,</span><br><span class="line">          //     function (val) &#123;</span><br><span class="line">          //       this.innerHTML = val;</span><br><span class="line">          //     &#125;,</span><br><span class="line">          //     val</span><br><span class="line">          //   );</span><br><span class="line">          // &#125;,</span><br><span class="line"></span><br><span class="line">          // version: &quot;6.1.1&quot;,</span><br><span class="line">          // length: 1,</span><br><span class="line">          // size: function () &#123;</span><br><span class="line">          //   return this.length;</span><br><span class="line">          // &#125;,</span><br><span class="line">        &#125;;</span><br><span class="line">        jQuery.fn.init.prototype = jQuery.fn;</span><br><span class="line"></span><br><span class="line">        //提供each扩展方法</span><br><span class="line">        jQuery.each = function (object, callback, args) &#123;</span><br><span class="line">          //通过for循环的方式来遍历jQuery对象中的每个DOM元素。</span><br><span class="line">          for (var i = 0; i &lt; object.length; i++) &#123;</span><br><span class="line">            // 在每个DOM元素上调用回调函数</span><br><span class="line">            callback.call(object[i], args);</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">          return object; //返回jQuery对象。</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        // jQuery.extend = jQuery.fn.extend = function (obj) &#123;</span><br><span class="line">        //   for (var prop in obj) &#123;</span><br><span class="line">        //     this[prop] = obj[prop];</span><br><span class="line">        //   &#125;</span><br><span class="line">        //   return this;</span><br><span class="line">        // &#125;;</span><br><span class="line">        jQuery.extend = jQuery.fn.extend = function () &#123;</span><br><span class="line">          var destination = arguments[0],</span><br><span class="line">            source = arguments[1];</span><br><span class="line">          //如果存在两个参数，并且都是对象</span><br><span class="line">          if (typeof destination === &quot;object&quot; &amp;&amp; typeof source === &quot;object&quot;) &#123;</span><br><span class="line">            //把第二个对象合并到第一个参数对象中，并返回合并后的对象</span><br><span class="line">            for (var property in source) &#123;</span><br><span class="line">              destination[property] = source[property];</span><br><span class="line">            &#125;</span><br><span class="line">            return destination;</span><br><span class="line">          &#125; else &#123;</span><br><span class="line">            for (var prop in destination) &#123;</span><br><span class="line">              this[prop] = destination[prop];</span><br><span class="line">            &#125;</span><br><span class="line">            return this;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        // 开发jqueyr</span><br><span class="line">        window.jQuery = window.$ = jQuery;</span><br><span class="line">      &#125;)(window);</span><br><span class="line"></span><br><span class="line">      jQuery.fn.extend(&#123;</span><br><span class="line">        html: function (val) &#123;</span><br><span class="line">          jQuery.each(</span><br><span class="line">            this,</span><br><span class="line">            function (val) &#123;</span><br><span class="line">              this.innerHTML = val;</span><br><span class="line">            &#125;,</span><br><span class="line">            val</span><br><span class="line">          );</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      jQuery.fn.extend(&#123;</span><br><span class="line">        fontStyle: function (obj) &#123;</span><br><span class="line">          var defaults = &#123;</span><br><span class="line">            color: &quot;#ccc&quot;,</span><br><span class="line">            size: &quot;16px&quot;,</span><br><span class="line">          &#125;;</span><br><span class="line">          //如果有参数，会覆盖掉默认的参数</span><br><span class="line">          defaults = jQuery.extend(defaults, obj || &#123;&#125;);</span><br><span class="line"></span><br><span class="line">          // console.log(&quot;this==&quot;, this);//init &#123;0: p, 1: p, length: 2, context: document&#125;</span><br><span class="line">          //为每个DOM元素执设置样式.</span><br><span class="line">          jQuery.each(this, function () &#123;</span><br><span class="line">            //这里的this表示的是p标签，因为在each方法内部通过call改变了this指向，让this指向了每个遍历得到的p元素</span><br><span class="line"></span><br><span class="line">            this.style.color = defaults.color;</span><br><span class="line">            this.style.fontSize = defaults.size;</span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">      window.onload = function () &#123;</span><br><span class="line">        // console.log($(&quot;div&quot;).length);</span><br><span class="line">        $(&quot;div&quot;).html(&quot;&lt;h2&gt;hello&lt;h2&gt;&quot;);</span><br><span class="line">        $(&quot;p&quot;).fontStyle(&#123;</span><br><span class="line">          color: &quot;red&quot;,</span><br><span class="line">          size: &quot;30px&quot;,</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;;</span><br><span class="line">      //   console.log($().version);</span><br><span class="line">      //   console.log($()._size()); // 0</span><br><span class="line">      //   console.log($().size()); // 0</span><br><span class="line">      //   var jq = new $();</span><br><span class="line">      //   console.log(jq.version); // 6.1.1</span><br><span class="line">      //   console.log(jq.size());</span><br><span class="line">    &lt;/script&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">    &lt;div&gt;&lt;/div&gt;</span><br><span class="line">    &lt;p&gt;学习前端&lt;/p&gt;</span><br><span class="line">    &lt;p&gt;学习前端&lt;/p&gt;</span><br><span class="line">  &lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，将<code>jQuery</code>库放在匿名函数中，然后进行自调用，并且传入<code>window</code>对象。</p>
<p>在上面所添加的代码中还要注意如下语句：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">jQuery</span> = <span class="variable language_">window</span>.<span class="property">$</span> = jQuery;</span><br></pre></td></tr></table></figure>

<p>以上语句的作用：把闭包中的私有变量<code>jQuery</code>传递给<code>window</code>对象的<code>jQuery</code>属性。这样就可以在全局作用域中通过<code>jQuery</code>变量来访问闭包体内的<code>jQuery</code>框架了。</p>
<p>以上就是我们模拟的<code>jQuery</code>库。</p>
<h1 id="五、DOM与事件"><a href="#五、DOM与事件" class="headerlink" title="五、DOM与事件"></a>五、DOM与事件</h1><h2 id="1、选择器"><a href="#1、选择器" class="headerlink" title="1、选择器"></a>1、选择器</h2><p><code>getElementById()</code>:通过<code>id</code>来查找对应的元素。</p>
<p><code>getElementsByClassName()</code>:通过类名来查找对应的元素，返回的是一个<code>HTMLCollection</code>对象。</p>
<p><code>getElementsByName()</code>:通过元素的<code>name</code>属性查找对应的元素，返回的是<code>NodeList</code>对象，它是一个类似于数组的结构。</p>
<p><code>getElementsByTagName()</code>: 通过标签的名称来查找对应的元素，返回的是<code>HTMLCollection</code>对象。</p>
<p><code>querySelector</code>：该选择器返回的是在基准元素下，选择器匹配到的元素集合中的第一个元素。该选择器的参数接收的是一个<code>css</code>选择</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">h4</span>&gt;</span>标题内容<span class="tag">&lt;/<span class="name">h4</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">span</span>&gt;</span>span标签内容<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">       段落内容</span><br><span class="line">       <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第一个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第二个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">   <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;p span&quot;</span>).<span class="property">innerHTML</span>);<span class="comment">// 获取p标签中第一个span标签中的内容，所以输出结果为:段落中的第一个span标签</span></span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;h4,span&quot;</span>).<span class="property">innerHTML</span>);<span class="comment">//获取第一个h4或者是span元素的内容：所以输出结果为：标题内容</span></span></span><br><span class="line"><span class="language-javascript">       <span class="keyword">var</span> ele = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;p&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">   <span class="variable language_">console</span>.<span class="title function_">log</span>(ele.<span class="title function_">querySelector</span>(<span class="string">&quot;div span&quot;</span>).<span class="property">innerHTML</span>);<span class="comment">//段落中的第一个span标签。</span></span></span><br><span class="line"><span class="language-javascript">     <span class="comment">// 首先先找到`p`元素，然后看一下p元素下面有没有div,我们发现没有，但是依然能够匹配到span元素。</span></span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//原因是：在匹配的过程中会优先找出最外层div元素下的span元素的集合，然后在判断span元素是否属于p元素的子元素，最后返回</span></span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//第一个匹配到的span元素的值。</span></span></span><br><span class="line"><span class="language-javascript"> </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>下面，把<code>HTML</code>文档的结构修改成如下的形式：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h4</span>&gt;</span>标题内容<span class="tag">&lt;/<span class="name">h4</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">span</span>&gt;</span>span标签内容<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--这里增加了一个p标签--&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span>第一个段落<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">        段落内容</span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第一个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第二个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>执行如下代码会出现异常：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> ele = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;p&quot;</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(ele.<span class="title function_">querySelector</span>(<span class="string">&quot;div span&quot;</span>).<span class="property">innerHTML</span>);<span class="comment">//Cannot read property &#x27;innerHTML&#x27; of null</span></span><br></pre></td></tr></table></figure>

<p>原因：会找到第一个<code>p</code>元素,然后看一下<code>p</code>标签中是否有<code>div</code>,发现没有，但是会找出最外层<code>div</code>下的所有<code>span</code>元素的集合，看一下<code>span</code>元素是否属于<code>p</code>元素，而第一个<code>p</code>元素中没有<code>span</code>元素，所以抛出异常。</p>
<p><code>querySelectorAll()</code>选择器：</p>
<p><code>querySelectorAll</code>选择器与<code>querySelector</code>选择器的区别是：<code>querySelectAll</code>选择器会获取到基准元素下匹配到所有子元素的集合。返回的是一个<code>NodeList</code>集合。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h4</span>&gt;</span>标题内容<span class="tag">&lt;/<span class="name">h4</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">span</span>&gt;</span>span标签内容<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">p</span>&gt;</span></span><br><span class="line">        段落内容</span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第一个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span><span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>段落中的第二个span标签<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	 <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;span&quot;</span>));<span class="comment">//返回所有的span标签。</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>下面，再来看一段代码：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;bar&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;inner&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="comment">// 获取container下的所有div元素。</span></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> div1 = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;#container div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(div1);<span class="comment">// NodeList(3) [div.bar, div.foo, div.inner]</span></span></span><br><span class="line"><span class="language-javascript">   </span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="2、HTMLCollection对象与NodeList对象区别"><a href="#2、HTMLCollection对象与NodeList对象区别" class="headerlink" title="2、HTMLCollection对象与NodeList对象区别"></a>2、HTMLCollection对象与NodeList对象区别</h2><p>在介绍前面的选择器的时候，它们返回的值有些是<code>HTMLCollection</code>对象，有些是<code>NodeList</code>对象，它们有什么区别？</p>
<p><code>HTMLCollection</code>对象具有<code>1ength</code>属性，返回集合的长度，可以通过<code>item()</code>和<code>namedItem()</code>函数来访问特定的元素。</p>
<p><code>item()</code>函数：通过序号索引值来获取特定的某个节点，超过索引则返回<code>null</code>.</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;bar&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;inner&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> main = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;container&quot;</span>).<span class="property">children</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(main); <span class="comment">//HTMLCollection</span></span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(main.<span class="title function_">item</span>(<span class="number">0</span>)); <span class="comment">//输出:&lt;div class=&quot;bar&quot;&gt;&lt;/div&gt;</span></span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(main.<span class="title function_">item</span>(<span class="number">1</span>)); <span class="comment">// 输出:foo元素</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><code>namedItem()</code>函数：该函数用来返回一个节点，首先通过<code>id</code>属性去匹配，然后如果没有匹配到则使用<code>name</code>属性匹配，如果还没有匹配到则返回<code>null</code>. 当出现重复的<code>id</code>或者<code>name</code>属性时，只返回匹配到的第一个值。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> form1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>).<span class="property">children</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(form1.<span class="title function_">namedItem</span>(<span class="string">&quot;userPwd&quot;</span>));<span class="comment">//   &lt;input type=&quot;password&quot; id=&quot;password&quot; name=&quot;userPwd&quot; /&gt;</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><code>NodeList</code>对象也具有<code>length</code>属性，返回集合的长度，同样也有<code>item</code>函数，也是通过索引定位子元素的位置。但是<code>NodeList</code>对象没有<code>namedItem</code>方法。</p>
<p><code>HTMLCollection</code>对象与<code>NodeList</code>对象都是类似数组的结构，如果想调用数组中的方法，需要通过<code>call()</code>函数或者是<code>apply()</code>函数，转换为真正的数组后，可以使用数组中的函数。</p>
<p>同时，当我们对<code>DOM</code>树新增或者是删除一个节点的时候，都会立即的放映在<code>HTMLCollection</code>对象与<code>NodeList</code>对象中。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="comment">//获取HTMLCollection集合</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> form1Children = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>).<span class="property">children</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">// 获取form元素</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> form1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(form1Children.<span class="property">length</span>); <span class="comment">// 2 HTMLCollection中有两个子元素</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> input = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;input&quot;</span>); <span class="comment">//创建input元素</span></span></span><br><span class="line"><span class="language-javascript">    form1.<span class="title function_">appendChild</span>(input); <span class="comment">// 把创建的input元素添加到form元素中</span></span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(form1Children.<span class="property">length</span>); <span class="comment">// 3 可以看到HTMLCollection立即受到了影响</span></span></span><br></pre></td></tr></table></figure>

<p>最后，总结一下<code>HTMLCollection</code>对象与<code>NodeList</code>对象的相同点与不同点</p>
<p>相同点：</p>
<p>第一：都是类似数组的结构，有<code>length</code>属性，可以通过<code>call()</code>函数或者是<code>apply()</code>函数转换成数组，使用数组中的函数。</p>
<p>第二：都用<code>item</code>函数，通过索引值获取相应的元素。</p>
<p>第三：都是实时的，当在<code>DOM</code>树上添加元素或者是删除元素，都会立即反应到<code>HTMLCollection</code>对象和<code>NodeList</code>对象上。</p>
<p>不同点：</p>
<p>第一：<code>HTMLCollection</code>对象中，有<code>namedItem()</code>函数，而<code>NodeList</code>对象中没有.</p>
<p>第二：<code>NodeList</code>对象中存储的是元素节点的集合，包括元素，以及节点，例如<code>text</code>文本节点，而<code>HTMLCollection</code>对象中只包含了元素的集合。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      用户名<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">      用户密码<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="comment">//获取HTMLCollection集合</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> form1Children = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>).<span class="property">children</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(form1Children);</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//获取NodeList对象</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> formNodes = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>).<span class="property">childNodes</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(formNodes);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>通过查看浏览器控制台输出的结果，可以看出<code>HTMLCollection</code>对象与<code>NodeList</code>对象的区别。</p>
<h2 id="3、常见的DOM操作有哪些？"><a href="#3、常见的DOM操作有哪些？" class="headerlink" title="3、常见的DOM操作有哪些？"></a>3、常见的DOM操作有哪些？</h2><p><strong>添加节点</strong></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      用户名<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">      用户密码<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	<span class="keyword">var</span> form1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//创建一个input元素</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> newInput = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;input&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//创建属性</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> newAttr = <span class="variable language_">document</span>.<span class="title function_">createAttribute</span>(<span class="string">&quot;type&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    newAttr.<span class="property">value</span> = <span class="string">&quot;password&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//将属性绑定到元素上</span></span></span><br><span class="line"><span class="language-javascript">    newInput.<span class="title function_">setAttributeNode</span>(newAttr);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//创建一个文本节点</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> newTextNode = <span class="variable language_">document</span>.<span class="title function_">createTextNode</span>(<span class="string">&quot;用户密码&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    form1.<span class="title function_">appendChild</span>(newTextNode); <span class="comment">//添加文本节点</span></span></span><br><span class="line"><span class="language-javascript">    form1.<span class="title function_">appendChild</span>(newInput);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>删除节点</strong></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      用户名<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">      用户密码<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> form1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;form1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> nodeChilds = form1.<span class="property">childNodes</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(nodeChilds);</span></span><br><span class="line"><span class="language-javascript">    form1.<span class="title function_">removeChild</span>(nodeChilds[<span class="number">0</span>]);</span></span><br><span class="line"><span class="language-javascript">    form1.<span class="title function_">removeChild</span>(nodeChilds[<span class="number">0</span>]);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们想将表单中的<code>用户名</code>这一项内容删除掉。</p>
<p>首先获取<code>form</code>表单，然后在获取对应的子元素。</p>
<p>通过执行<code>removeChild</code>方法删除第一个元素，而第一个元素是<code>用户名</code>这个文本字符串，</p>
<p>下面还要删除文本框，所以再次调用了<code>removeChild</code>函数，注意由于前面已经删除了<code>用户名</code>这个文本元素了，所以文本框成为了第一个元素，所以这里写到索引值也是0.</p>
<p><strong>删除文本框的<code>id</code>属性</strong></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;form1&quot;</span>&gt;</span></span><br><span class="line">      用户名<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">      用户密码<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userPwd&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	 <span class="keyword">var</span> input = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;#userName&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    input.<span class="title function_">removeAttribute</span>(<span class="string">&quot;id&quot;</span>);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p> <strong>修改节点</strong></p>
<p><strong>修改元素节点</strong></p>
<p>修改元素的节点的操作，一般是直接用新的节点替换旧的节点。关于节点的替换可以使用，<code>replaceChild</code>函数来实现，该函数的调用是通过父元素来调用的，例如：把<code>div1</code>中的内容替换掉，这里就需要通过<code>container.replaceChild</code>方法来完成，<code>replaceChild</code>方法需要两个参数，第一个参数表示的是新元素，第二个参数表示的是旧元素。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">   <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> container = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;container&quot;</span>); <span class="comment">//获取父元素container</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>); <span class="comment">//获取子元素</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> newDiv = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>); <span class="comment">// 创建一个新的div元素</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> newText = <span class="variable language_">document</span>.<span class="title function_">createTextNode</span>(<span class="string">&quot;nihao&quot;</span>); <span class="comment">//创建一个文本内容</span></span></span><br><span class="line"><span class="language-javascript">      newDiv.<span class="title function_">appendChild</span>(newText); <span class="comment">//把创建的文本内容添加到新的div中</span></span></span><br><span class="line"><span class="language-javascript">      container.<span class="title function_">replaceChild</span>(newDiv, div1); <span class="comment">//用新的div替换旧的div,完成节点的修改操作。</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>修改属性节点</strong></p>
<p>修改属性的节点，我们可以通过<code>setAttribute()</code>函数来完成，如果想获取属性节点可以通过<code>getAttribute()</code>函数来完成。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span> <span class="attr">style</span>=<span class="string">&quot;color: red&quot;</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	   <span class="keyword">var</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      div1.<span class="title function_">setAttribute</span>(<span class="string">&quot;style&quot;</span>, <span class="string">&quot;color:blue&quot;</span>); <span class="comment">//设置style属性</span></span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">console</span>.<span class="title function_">log</span>(div1.<span class="title function_">getAttribute</span>(<span class="string">&quot;style&quot;</span>)); <span class="comment">// 获取style属性的值</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>修改属性节点除了通过<code>setAttribute()</code>方法完成以外，还可以通过属性名直接进行修改</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span> <span class="attr">style</span>=<span class="string">&quot;color: red&quot;</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      div1.<span class="property">style</span>.<span class="property">color</span> = <span class="string">&quot;blue&quot;</span>;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>但是通过这种方式进行修改，还需要注意一个问题：直接修改的属性名与元素节点中的属性名不一定是一致的。例如<code>class</code>这个属性，在<code>javascript</code>中是关键字，不能直接作为属性使用，这时需要通过<code>className</code>来完成。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span> <span class="attr">style</span>=<span class="string">&quot;color: red&quot;</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span>前端学习<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> div2 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div2&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      div2.<span class="property">className</span> = <span class="string">&quot;bar&quot;</span>; <span class="comment">//注意这里使用的是className</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>通过查看浏览器控制台，可以看到对应的样式发生了修改。</p>
<p><strong>修改文本节点</strong></p>
<p>文本节点的修改，可以通过<code>innerHTML</code>属性来完成。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span> <span class="attr">style</span>=<span class="string">&quot;color: red&quot;</span>&gt;</span>hello<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span>前端学习<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	  <span class="keyword">var</span> div2 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div2&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      div2.<span class="property">innerHTML</span> = <span class="string">&quot;Vue 学习&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">&lt;/script?&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="4、DOM性能问题"><a href="#4、DOM性能问题" class="headerlink" title="4、DOM性能问题"></a>4、DOM性能问题</h2><p><code>Dom</code>操作非常消耗性能，应该尽量避免频繁的操作<code>DOM</code>.</p>
<p>导致浏览器重绘，重新渲染，比较消耗<code>cpu</code>资源，比较消耗性能。</p>
<p>提升性能的方案：</p>
<p>第一：对<code>DOM</code>查询操作进行缓存</p>
<p>第二：将频繁操作修改为一次性操作</p>
<p>首先看第一种情况：</p>
<p>这里需要对页面中所有<code>p</code>标签内文字调整大小(单击按钮完成)</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//不缓存的结果</span></span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;p&quot;</span>).<span class="property">length</span>; i++) &#123;</span><br><span class="line">       <span class="comment">//每次循环，都会计算lenght,频繁进行DOM查询</span></span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> pList = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;p&quot;</span>);</span><br><span class="line">     <span class="keyword">const</span> length = pList.<span class="property">length</span>;</span><br><span class="line">     <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">       <span class="comment">//缓存length,只进行一次DOM查询</span></span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure>

<p>下面看一下第二种情况：</p>
<p>需求：页面中有一个<code>ul</code>列表，需要单击按钮一次性插入10个或者100个<code>li</code>?</p>
<p>传统的做法：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">id</span>=<span class="string">&quot;list&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> listNode = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">const</span> li = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">        li.<span class="property">innerHTML</span> = <span class="string">`item<span class="subst">$&#123;i&#125;</span>`</span>;</span><br><span class="line">        list.<span class="title function_">appendChild</span>(li);</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>执行上面的代码，可以实现对应的需求，但是问题是上面的操作是频繁操作<code>dom</code>，性能比较低。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> listNode = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">      <span class="comment">//创建一个文档片段，文档片段存在于内存中，并不在DOM树中，所以此时还没有插入到DOM中</span></span><br><span class="line">      <span class="comment">//也就是先将dom插入到临时区域中</span></span><br><span class="line">      <span class="keyword">const</span> frag = <span class="variable language_">document</span>.<span class="title function_">createDocumentFragment</span>();</span><br><span class="line">      <span class="comment">//执行插入</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">const</span> li = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">        li.<span class="property">innerHTML</span> = <span class="string">`item<span class="subst">$&#123;i&#125;</span>`</span>;</span><br><span class="line">        frag.<span class="title function_">appendChild</span>(li);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//都完成后，再插入到DOM树中</span></span><br><span class="line">      listNode.<span class="title function_">appendChild</span>(frag);</span><br></pre></td></tr></table></figure>

<h2 id="5、什么是事件传播"><a href="#5、什么是事件传播" class="headerlink" title="5、什么是事件传播"></a>5、什么是事件传播</h2><p>在浏览器中，<code>JavaScript</code>和<code>HTML</code>之间的交互是通过事件实现的，常用的事件包括了鼠标点击的事件，鼠标移动事件等等。</p>
<p>当事件发生以后，会触发绑定在元素上的事件处理程序，执行相应的操作。</p>
<p>问题是当事件发生后，事件是怎样传播的呢？</p>
<p>事件发生后会在目标节点和根节点之间按照特定的顺序进行传播，路径经过的节点都会接收到事件。</p>
<p>这里的特定顺序是怎样的顺序呢？</p>
<p>第一种：事件传递的顺序是先触发最外层的元素，然后依次向内传播，这样的传递顺序我们称之为事件的捕获阶段。</p>
<p>第二种：事件传递的顺序是先触发最内层的元素，然后依次向外进行传播，这样的传递顺序我们称之为事件冒泡阶段。</p>
<p>当然，一个完整的事件传播包含了三个阶段</p>
<p>首先就是事件的捕获阶段</p>
<p>然后是事件的目标阶段，目标阶段指的就是事件已经到达目标元素。</p>
<p>最后是事件的冒泡阶段</p>
<p>以上就是关于事件传播的描述</p>
<h2 id="6、什么是事件的捕获"><a href="#6、什么是事件的捕获" class="headerlink" title="6、什么是事件的捕获"></a>6、什么是事件的捕获</h2><p>关于事件捕获，在上一小节，我们已经介绍过：事件的传递是从最外层开始，依次向内传播，在捕获阶段，事件从<code>window</code>开始，一直到触发事件的元素。</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">window----&gt; document----&gt; html----&gt; body ----&gt;目标元素</span><br></pre></td></tr></table></figure>

<p>如下代码所示：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span> <span class="attr">border</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">td</span>&gt;</span>单元格内容<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> table = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tbody = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tr = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> td = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      table.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">      tbody.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">      tr.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">      td.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，有一个表格，给表格中的每个元素通过<code>addEventListener</code>方法绑定了单击事件，同时该方法的第三个参数，设置为了<code>true</code>,这样就表明事件将在捕获阶段发生。</p>
<p>所以当我们单击<code>td</code>单元格的时候，事件的执行结果是：<code>table</code>,<code>tbody</code>,<code>tr</code>,<code>td</code>.也就是说事件从<code>table</code>开始，依次向下传播。这个传播的过程就是事件捕获。</p>
<h2 id="7、什么是事件冒泡"><a href="#7、什么是事件冒泡" class="headerlink" title="7、什么是事件冒泡"></a>7、什么是事件冒泡</h2><p>关于事件的冒泡，在前面也已经提到过：事件传递的顺序是先触发最内层的元素，然后依次向外进行传播，这样的传递顺序我们称之为事件冒泡阶段。</p>
<p>如下代码所示：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span> <span class="attr">border</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">td</span>&gt;</span>单元格内容<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> table = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tbody = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tr = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> td = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      table.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      tbody.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      tr.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>上面的代码，我们将<code>addEventListener</code>方法的第三个参数<code>true</code>去掉了，这时就有事件的捕获变成了事件的冒泡。默认值为(<code>false</code>).</p>
<p>但单击单元格的时候，执行的结果为：<code>td</code>,<code>tr</code>,<code>tbody</code>,<code>table</code>, 这个过程就是事件的冒泡。</p>
<h2 id="8、阻止事件冒泡"><a href="#8、阻止事件冒泡" class="headerlink" title="8、阻止事件冒泡"></a>8、阻止事件冒泡</h2><p>现在，我们已经了解了事件冒泡的过程，但是在很多的情况下，我们需要阻止事件冒泡的发生。</p>
<p>例如：在上一小节的案例中，当我们单击了单元格后，不仅触发单元格元素的事件，同时也会触发其它元素的事件，而这里我们只希望触发单元格的事件。所以这里需要阻止事件的冒泡。</p>
<p>阻止事件的冒泡需要使用：<code>event.stopPropagation()</code>函数</p>
<p>如下案例：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">var</span> table = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;table&quot;</span>);</span><br><span class="line">    <span class="keyword">var</span> tbody = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tbody&quot;</span>);</span><br><span class="line">    <span class="keyword">var</span> tr = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tr&quot;</span>);</span><br><span class="line">    <span class="keyword">var</span> td = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;td&quot;</span>);</span><br><span class="line">    table.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;table&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    tbody.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tbody&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    tr.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tr&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span><br><span class="line">      <span class="comment">//阻止了事件的冒泡操作</span></span><br><span class="line">      event.<span class="title function_">stopPropagation</span>();</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在单元格的事件处理函数中，通过<code>event.stopPropagation()</code>方法阻止了事件的冒泡。</p>
<p>与<code>stopPropagation()</code>函数相对的还有一个<code>stopImmediatePropagation</code>函数，它们两者之间有什么区别呢？</p>
<p><code>stopPropagation()</code>：函数会阻止事件冒泡，其它事件处理程序仍然可以调用</p>
<p><code>stopImmediatePropagation</code>函数不仅可以阻止事件冒泡，也会阻止其它事件处理程序的调用。</p>
<p>如下代码所示：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">table</span> <span class="attr">border</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="name">td</span>&gt;</span>单元格内容<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> table = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> tbody = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> tr = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> td = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     table.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">     tbody.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">     tr.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">       <span class="comment">//单元格第一个单击事件</span></span></span><br><span class="line"><span class="language-javascript">     td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">       <span class="comment">//单元格第二个单击事件</span></span></span><br><span class="line"><span class="language-javascript">     td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="comment">//阻止了事件的冒泡操作</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">// event.stopImmediatePropagation();</span></span></span><br><span class="line"><span class="language-javascript">        event.<span class="title function_">stopPropagation</span>();</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td2&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">    <span class="comment">//   单元格第三个单击事件</span></span></span><br><span class="line"><span class="language-javascript">     td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td3&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，给单元格添加了三个单击的事件，同时第二个单击事件使用了<code>stopPropagation</code>方法来阻止冒泡行为。</p>
<p>执行结果如下：<code>td1</code>,<code>td2</code>,<code>td3</code></p>
<p>通过执行结果，可以看到单元格的三个单击事件全部触发，并且阻止了冒泡的行为。</p>
<p>如果使用<code>stopImmediatePropagation</code>方法，执行结果为：<code>td1</code>,<code>td2</code></p>
<p>通过执行的结果可以看到，阻止了冒泡的行为，但是没有触发单元格的第三个单击的事件，也就是说会阻止其它事件的执行。</p>
<h2 id="9、事件冒泡与事件捕获问题"><a href="#9、事件冒泡与事件捕获问题" class="headerlink" title="9、事件冒泡与事件捕获问题"></a>9、事件冒泡与事件捕获问题</h2><p>下面我们来看一段代码：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span> <span class="attr">border</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">td</span>&gt;</span>单元格内容<span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> table = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tbody = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> tr = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> td = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//事件捕获</span></span></span><br><span class="line"><span class="language-javascript">      table.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;table&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//事件冒泡</span></span></span><br><span class="line"><span class="language-javascript">      tbody.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tbody&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//事件捕获</span></span></span><br><span class="line"><span class="language-javascript">      tr.<span class="title function_">addEventListener</span>(</span></span><br><span class="line"><span class="language-javascript">        <span class="string">&quot;click&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;tr&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="literal">true</span></span></span><br><span class="line"><span class="language-javascript">      );</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//事件冒泡</span></span></span><br><span class="line"><span class="language-javascript">      td.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;td&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">   </span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，既有事件捕获又有事件冒泡，那么执行的结果是怎样的呢？</p>
<p>当单击<code>td</code>单元格后</p>
<p>执行结果：<code>table</code>,<code>tr</code>,<code>td</code>,<code>tbody</code></p>
<p>分析：前面我们讲解过，事件传播的循序是：先事件捕获阶段，然后事件的目标阶段，最后是事件冒泡阶段</p>
<p>所以说，在一个程序中有事件的捕获阶段，又有事件的冒泡阶段，会优先执行捕获阶段的事件。</p>
<p>所以上面代码整个执行的流程：</p>
<p>先执行<code>table</code>这个捕获阶段，输出<code>table</code>这个字符串</p>
<p>下面执行<code>tbody</code>，但是<code>tbody</code>绑定的是冒泡类的事件，所以不执行，跳过。</p>
<p>下面是<code>tr</code>,而<code>tr</code>是捕获类型的事件，所以会执行，输出字符串<code>tr</code></p>
<p>下面是<code>td</code>,由于我们单击的是<code>td</code>元素，所以该元素就是事件目标元素，则会执行，输出<code>td</code>字符串。</p>
<p>当单击了<code>td</code>元素以后，就开始进入了事件冒泡阶段。这时会冒泡到<code>tr</code>元素，但是<code>tr</code>元素绑定的是捕获阶段的事件，所以不执行，直接跳过，下面继续冒泡到了<code>tbody</code>元素，该元素绑定的是冒泡类型的事件，所以执行，输出字符串<code>tbody</code>.</p>
<p>下面继续冒泡，执行到<code>table</code>元素，该原生是捕获类型的事件，所以直接跳过，没有输出。</p>
<h2 id="10、Event对象使用"><a href="#10、Event对象使用" class="headerlink" title="10、Event对象使用"></a>10、Event对象使用</h2><p>在<code>JavaScrip</code>中，每触发一个事件，就会产生一个<code>Event</code>对象，在该对象中包含了所有与事件相关的内容，包括事件的元素，事件类型等。</p>
<p>当给某个元素绑定了事件处理程序后，就可以获取到<code>Event</code>对象，但是在不同的浏览器下，<code>Event</code>对象的实现还是有一定的差异的。</p>
<p>关于获取<code>Event</code>对象的方式有两种：</p>
<p>第一种：在事件的处理程序中，可以通过参数来获取<code>Event</code>对象。</p>
<p>第二种：在事件的处理程序中，可以通过<code>window.event</code>属性获取<code>Event</code>对象。</p>
<p>具体的示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;body&gt;</span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>单击<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//通过参数获取Event对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;event=&quot;</span>, event);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//通过window.event的方式来获取Event对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="keyword">var</span> windEvent = <span class="variable language_">window</span>.<span class="property">event</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;windEvent=&quot;</span>, windEvent);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//判断两种方式是否相等</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(event === windEvent);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"> &lt;/body&gt;</span><br></pre></td></tr></table></figure>

<p>在谷歌浏览器中，测试上面的代码，可以发现两种获取<code>Event</code>对象的方式是相等的。</p>
<p>但是注意，在其它的浏览中进行测试可能会出现不相等的情况，也就是有的浏览器会出现不支持<code>window.event</code>这种方式来获取<code>Event</code>对象，这里可以自行进行测试。</p>
<p>为了能够在获取事件对象的时候，支持不同的浏览器，我们可以做兼容性的处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;body&gt;</span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>单击<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">   <span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     <span class="keyword">var</span> eventFn = &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="attr">event</span>: <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">         <span class="keyword">return</span> e || <span class="variable language_">window</span>.<span class="property">event</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//通过参数获取Event对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;event=&quot;</span>, eventFn.<span class="title function_">event</span>(event));</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//通过window.event的方式来获取Event对象</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="keyword">var</span> windEvent = eventFn.<span class="title function_">event</span>(<span class="variable language_">window</span>.<span class="property">event</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;windEvent=&quot;</span>, windEvent);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="comment">//判断两种方式是否相等</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">       <span class="variable language_">console</span>.<span class="title function_">log</span>(event === windEvent);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">     &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中定义了<code>eventFn</code>对象，在该对象中有一个属性<code>event</code>,在该属性中，判断返回<code>Eevent</code>对象的方式。</p>
<p>在对应的事件处理函数中，可以调用<code>eventFn</code>对象中的<code>event</code>方法来获取<code>Event</code>对象。</p>
<p><strong>获取事件的目标元素</strong></p>
<p>在事件的处理程序中，我们可能需要获取 事件的目标元素。</p>
<p>在<code>IE</code>浏览器中，可以使用<code>event</code>对象中的<code>srcElement</code>属性来获取事件的目标元素，在非<code>IE</code>浏览器中可以通过<code>event</code>对象的<code>target</code>属性来获取事件的目标元素，当然在有的非<code>IE</code>浏览器下也支持<code>event</code>对象中的<code>srcElement</code>属性，目的是为了保持与<code>ie</code>保持一致，但是要注意的是并不是所有的非<code>IE</code>浏览器都支持<code>srcElement</code>属性。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">var</span> eventFn = &#123;</span><br><span class="line">        <span class="attr">event</span>: <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">          <span class="keyword">return</span> e || <span class="variable language_">window</span>.<span class="property">event</span>;</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line">      btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> event = eventFn.<span class="title function_">event</span>(event);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;target=&quot;</span>, event.<span class="property">target</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;srcElement=&quot;</span>, event.<span class="property">srcElement</span>);</span><br><span class="line">      &#125;);</span><br><span class="line"> &lt;/script&gt;   </span><br></pre></td></tr></table></figure>

<p>在谷歌浏览器中进行测试，都可以获取<code>target</code>属性和<code>srcElement</code>属性的值。</p>
<p>关于其它浏览器的情况，可以自行测试。</p>
<p>当然为了能够兼容其它的浏览器，可以做一下兼容的处理。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> eventFn = &#123;</span><br><span class="line">     <span class="attr">event</span>: <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> e || <span class="variable language_">window</span>.<span class="property">event</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">     <span class="attr">target</span>: <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">       <span class="keyword">return</span> e.<span class="property">target</span> || e.<span class="property">srcElement</span>;</span><br><span class="line">     &#125;,</span><br><span class="line">   &#125;;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line">   btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span><br><span class="line">     <span class="keyword">var</span> event = eventFn.<span class="title function_">event</span>(event);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;target=&quot;</span>, eventFn.<span class="title function_">target</span>(event));</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;srcElement=&quot;</span>, eventFn.<span class="title function_">target</span>(event));</span><br><span class="line">   &#125;);</span><br></pre></td></tr></table></figure>

<p>这里在<code>eventFn</code>对象中封装了一个<code>target</code>属性。</p>
<p><strong>阻止默认行为</strong></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"> <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;https://www.baidu.com&quot;</span> <span class="attr">id</span>=<span class="string">&quot;a1&quot;</span>&gt;</span>链接<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> a1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;a1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      a1.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        event.<span class="title function_">preventDefault</span>(); <span class="comment">//阻止默认行为</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">alert</span>(<span class="string">&quot;你点击了链接&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span>  </span><br></pre></td></tr></table></figure>

<p>关于<code>Event</code>对象中的其他内容，可以参考文档。</p>
<h2 id="11、介绍一下三种事件模型"><a href="#11、介绍一下三种事件模型" class="headerlink" title="11、介绍一下三种事件模型"></a>11、介绍一下三种事件模型</h2><p>关于<code>JavaScript</code>的事件模型有三类，分别是<code>DOM0</code>，<code>DOM2</code>,<code>DOM3</code></p>
<p><strong>DOM0事件模型</strong></p>
<p><code>DOM0</code>的事件模型指的是：将一个函数赋值给一个事件处理属性。</p>
<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> btn=<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;btn&#x27;</span>)</span><br><span class="line">btn.<span class="property">onclick</span>=<span class="keyword">function</span>(<span class="params"></span>)&#123;&#125;</span><br></pre></td></tr></table></figure>

<p>或者也可以采用如下的方式：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">onclick</span>=<span class="string">&quot;fn()&quot;</span>&gt;</span></span><br><span class="line">    单击</span><br><span class="line">    <span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">	<span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;hello&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>需要注意的是：<code>DOM0</code>事件模型的处理程序只支持冒泡阶段。</p>
<p><code>DOM0</code>事件模型的优点与缺点：</p>
<p>优点：实现起来非常简单，并且可以跨浏览器。</p>
<p>缺点：一个事件处理程序只能绑定一个函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;body&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span> <span class="attr">onclick</span>=<span class="string">&quot;btnClick()&quot;</span>&gt;</span>单击按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      btn.<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">function</span> <span class="title function_">btnClick</span>(<span class="params"></span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;123&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line">  &lt;/body&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们给按钮使用两种方法绑定了事件处理程序，但是<code>DOM0</code>这种事件模型只能绑定一个函数，并且在<code>JavaScript</code>中绑定事件处理程序的优先级高于在<code>HTML</code>元素中定义的事件处理程序，所以打印结果为<code>hello</code>.</p>
<p>如果删除元素绑定的事件，只需要将对应的事件处理程序设置为<code>null</code>即可</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">btn.onclick=null</span><br></pre></td></tr></table></figure>

<p><strong>DOM2事件模型</strong></p>
<p>针对<code>DOM2</code>事件模型不同的浏览器厂商制定了不同的的实现方式，主要分为<code>IE</code>浏览器和<code>非IE浏览器</code></p>
<p>在<code>IE10</code>及以下版本中只支持事件的冒泡，在<code>IE11</code>中同时支持事件的捕获与事件冒泡。在<code>IE10</code>及以下版本中，可以通过<code>attachEvent</code>函数来添加事件处理程序，通过<code>detachEvent</code>函数删除事件处理程序。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">element.<span class="title function_">attachEvent</span>(<span class="string">&#x27;on&#x27;</span>+ eventName,handler) <span class="comment">// 添加事件处理程序</span></span><br><span class="line">element.<span class="title function_">detachEvent</span>(<span class="string">&#x27;on&#x27;</span>+ eventName,handler) <span class="comment">//  删除事件处理程序</span></span><br></pre></td></tr></table></figure>

<p>在<code>IE11</code>和非<code>IE</code>浏览器中，同时支持事件捕获和事件冒泡两个阶段，可以通过<code>addEventListener()</code>函数添加事件处理程序，可以通过<code>removeEventListener()</code> 函数删除事件处理程序。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">addEventListener</span>(eventName,handler,useCapture) <span class="comment">//添加事件处理程序</span></span><br><span class="line"><span class="title function_">removeEventListener</span>(eventName,handler,useCapture) <span class="comment">// 删除事件处理程序</span></span><br></pre></td></tr></table></figure>

<p>其中<code>useCapture</code>如果为<code>true</code>表示支持事件捕获，为<code>false</code>b表示支持事件冒泡，默认是为<code>false</code></p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7%E4%B8%8E%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1.png"></p>
<p>通过上面的介绍，我们知道了<code>DOM2</code>的事件处理程序存在两种情况，那这两种实现的方式之间有没有相同点和不同点呢？</p>
<p><strong>相同点</strong></p>
<p>第一：在<code>DOM2</code>的事件处理中不管是<code>IE</code>浏览器还是非<code>IE</code>浏览器都支持对同一个事件绑定多个处理函数。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>单击按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;nihao&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>以上程序的输出结果为：<code>hello</code>,<code>nihao</code></p>
<p>第二：在需要删除绑定的事件的时候，，不能删除匿名函数，因为添加的函数和删除的函数必须是同一个函数。</p>
<p>下面的代码中，同时绑定和删除了<code>handler</code>函数，这样做是完全可以的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> btn=<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;btn&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> handle=<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;hello&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line">btn.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>,handle,<span class="literal">false</span>);</span><br><span class="line">btn.<span class="title function_">removeEventListener</span>(<span class="string">&#x27;click&#x27;</span>,handle)</span><br></pre></td></tr></table></figure>

<p>但是如果采用如下的删除方式是无法取消绑定的事件的。因为它们都是匿名函数，而并不是同一个函数。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">btn.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;hello&#x27;</span>)</span><br><span class="line">&#125;,<span class="literal">false</span>)</span><br><span class="line">btn.<span class="title function_">removeEventListener</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;&#125;)</span><br></pre></td></tr></table></figure>

<p> <strong>不同点</strong></p>
<p>第一：在<code>IE</code>浏览器中，使用<code>attachEvent</code>函数为同一个事件添加多个处理程序时，会按照添加的相反顺序执行。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span><br><span class="line">      btn.<span class="title function_">attachEvent</span>(<span class="string">&quot;onclick&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">      &#125;);</span><br><span class="line">      btn.<span class="title function_">attachEvent</span>(<span class="string">&quot;onclick&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;nihao&quot;</span>);</span><br><span class="line">      &#125;);</span><br><span class="line"> &lt;/script&gt;   </span><br></pre></td></tr></table></figure>

<p>当单击按钮的时候，先输出<code>nihao</code>,再输出<code>hello</code>.</p>
<p>第二：在<code>IE</code>浏览中，<code>attachEvent</code>函数添加的事件处理程序会在全局作用域中运行，因此<code>this</code>指向的是<code>window</code>.</p>
<p>在非<code>IE</code>浏览器中，<code>addEventListener()</code>函数添加的处理程序在指定的元素内部执行，<code>this</code>指向所绑定的元素。</p>
<p>既然<code>DOM2</code>事件的处理有浏览器的兼容性问题，那应该怎样进行处理呢？</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="title class_">EventHandler</span> = &#123;</span><br><span class="line">       <span class="attr">addEventHandler</span>: <span class="keyword">function</span> (<span class="params">ele, type, handler</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (ele.<span class="property">addEventListener</span>) &#123;</span><br><span class="line">           ele.<span class="title function_">addEventListener</span>(type, handler);</span><br><span class="line">         &#125; <span class="keyword">else</span> <span class="keyword">if</span> (ele.<span class="property">attachEvent</span>) &#123;</span><br><span class="line">           ele.<span class="title function_">attachEvent</span>(<span class="string">&quot;on&quot;</span> + type, handler);</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           ele[<span class="string">&quot;on&quot;</span> + type] = handler;</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">removeEventHandler</span>: <span class="keyword">function</span> (<span class="params">ele, type, handler</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (ele.<span class="property">addEventListener</span>) &#123;</span><br><span class="line">           ele.<span class="title function_">removeEventHandler</span>(type, handler);</span><br><span class="line">         &#125; <span class="keyword">else</span> <span class="keyword">if</span> (ele.<span class="property">detachEvent</span>) &#123;</span><br><span class="line">           ele.<span class="title function_">detachEvent</span>(<span class="string">&quot;on&quot;</span> + type, handler);</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           ele[<span class="string">&quot;on&quot;</span> + type] = <span class="literal">null</span>;</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br></pre></td></tr></table></figure>



<p><strong>DOM3事件模型</strong></p>
<p><code>DOM3</code>事件模型中允许自定义事件，自定义事件有<code>createEvent(&quot;CustomEvent&quot;)</code>函数来完成。返回的对象有一个<code>initCustomEvent</code>（）方法接收如下四个参数。</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">1）type：字符串，触发的事件类型，自定义。例如 “keyDown”，“selectedChange”;</span><br><span class="line">　　2）bubble（布尔值）：标示事件是否应该冒泡；</span><br><span class="line">　　3）cancelable(布尔值)：标示事件是否可以取消；</span><br><span class="line">　　4）detail（对象）：任意值，保存在event对象的detail属性中；</span><br></pre></td></tr></table></figure>

<p>具体的示例代码如下</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span>&gt;</span>监听自定义事件<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>单击<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> customeEvent;</span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//在立即执行函数中创建自定义事件</span></span></span><br><span class="line"><span class="language-javascript">     (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="comment">//判断浏览器是否支持DOM3事件处理程序，如果条件成立表示支持,固定写法</span></span></span><br><span class="line"><span class="language-javascript">       <span class="keyword">if</span> (<span class="variable language_">document</span>.<span class="property">implementation</span>.<span class="title function_">hasFeature</span>(<span class="string">&quot;CustomEvents&quot;</span>, <span class="string">&quot;3.0&quot;</span>)) &#123;</span></span><br><span class="line"><span class="language-javascript">         <span class="keyword">var</span> user = &#123; <span class="attr">userName</span>: <span class="string">&quot;zhangsan&quot;</span> &#125;;</span></span><br><span class="line"><span class="language-javascript">         customeEvent = <span class="variable language_">document</span>.<span class="title function_">createEvent</span>(<span class="string">&quot;CustomEvent&quot;</span>); <span class="comment">//创建自定义事件</span></span></span><br><span class="line"><span class="language-javascript">         customeEvent.<span class="title function_">initCustomEvent</span>(<span class="string">&quot;myEvent&quot;</span>, <span class="literal">true</span>, <span class="literal">false</span>, user);</span></span><br><span class="line"><span class="language-javascript">       &#125;</span></span><br><span class="line"><span class="language-javascript">     &#125;)();</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//监听自定义事件</span></span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//通过addEventListener()函数监听自定义的事件`myEvent`</span></span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     div1.<span class="title function_">addEventListener</span>(<span class="string">&quot;myEvent&quot;</span>, <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;用户名是:&quot;</span>, e.<span class="property">detail</span>.<span class="property">userName</span>);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">     <span class="comment">//触发自定义事件</span></span></span><br><span class="line"><span class="language-javascript">     <span class="keyword">var</span> btn1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btn&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">       div1.<span class="title function_">dispatchEvent</span>(customeEvent);</span></span><br><span class="line"><span class="language-javascript">     &#125;);</span></span><br><span class="line"><span class="language-javascript">   </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>以上就是<code>DOM3</code>事件模型的案例。</p>
<h2 id="12、介绍一下事件委托"><a href="#12、介绍一下事件委托" class="headerlink" title="12、介绍一下事件委托"></a>12、介绍一下事件委托</h2><p>事件冒泡的一个应用就是事件代理，也叫做事件委托</p>
<p>事件委托：利用事件冒泡的特性，将本应该注册在子元素上的处理事件注册在父元素上。</p>
<p>例如：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span>&gt;</span>a1<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span>&gt;</span>a2<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span>&gt;</span>a3<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span>&gt;</span>增加按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中有很多的<code>a</code>标签，如果给每个<code>a</code>标签添加单击事件比较麻烦，同时采用这种方式添加事件还会导致占用内存比较多，你可以想象一下，如果<code>a</code>标签比较多的话，是不是会占用更多的内存。</p>
<p>那应该怎样解决这个问题呢？</p>
<p>可以通过事件委托的机制。也就是将事件绑定到父元素上，然后通过事件冒泡的原理，来解决这个问题。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">const</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span><br><span class="line">     div1.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> target = e.<span class="property">target</span>;</span><br><span class="line">       <span class="keyword">if</span> (target.<span class="property">nodeName</span>.<span class="title function_">toLowerCase</span>() === <span class="string">&quot;a&quot;</span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(target.<span class="property">innerHTML</span>);</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;);</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们通过事件委托的方式解决了对应的问题，当然，这里你可能问，在<code>div</code>标签下的<code>a</code>标签所做的操作都是一样的，那么能不能针对不同的元素所做的操作如果不一样，事件委托能否处理呢？</p>
<p>答案是可以处理的。</p>
<p>下面我们把上面的程序改造一下：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;div1&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span> <span class="attr">id</span>=<span class="string">&quot;a1&quot;</span>&gt;</span>a1<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span> <span class="attr">id</span>=<span class="string">&quot;a2&quot;</span>&gt;</span>a2<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;#&quot;</span> <span class="attr">id</span>=<span class="string">&quot;a3&quot;</span>&gt;</span>a3<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">button</span>&gt;</span>增加按钮<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> div1 = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      div1.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> target = e.<span class="property">target</span>;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">switch</span> (target.<span class="property">id</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">case</span> <span class="string">&quot;a1&quot;</span>:</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;针对a1进行操作&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">break</span>;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">case</span> <span class="string">&quot;a2&quot;</span>:</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;针对a2进行操作&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">break</span>;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">case</span> <span class="string">&quot;a3&quot;</span>:</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;针对a3进行操作&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">break</span>;</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，给每个<code>a</code>标签，添加了<code>id</code>属性，通过<code>switch</code>结构进行判断，然后执行不同的操作。</p>
<p>下面，我们再来看一个关于事件委托的应用问题：</p>
<p>在一个<code>ul</code>标签中，包含了<code>5</code>个<code>li</code>，需要单击每个<code>li</code>标签，输出标签中的内容。同时在页面中添加一个按钮，单击按钮创建一个新的<code>li</code>元素，单击新创建的<code>li</code>元素也可以输出对应的内容。</p>
<p>我们想到的实现方式如下：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span>a1<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span>a2<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span>a3<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span>a4<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span>a5<span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>添加<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//通过querySelectorAll方法获取所有的li元素</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//通过for循环遍历的方式，给每个li添加单击事件</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> children = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;li&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; children.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">        children[i].<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">innerHTML</span>);</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//获取按钮</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;#btn&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//获取ul标签</span></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">var</span> ul = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;ul&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//给按钮添加单击事件</span></span></span><br><span class="line"><span class="language-javascript">      btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//创建li</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> newLi = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//创建文本节点</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> newText = <span class="variable language_">document</span>.<span class="title function_">createTextNode</span>(<span class="string">&quot;a6&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//将文本添加到新创建的li标签上</span></span></span><br><span class="line"><span class="language-javascript">        newLi.<span class="title function_">appendChild</span>(newText);</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//把创建的li添加到ul上</span></span></span><br><span class="line"><span class="language-javascript">        ul.<span class="title function_">appendChild</span>(newLi);</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>执行上面的代码：打击<code>a1--a5</code>都可以获取内容，单击按钮也可以添加一个新的<code>li</code>元素，但是问题是单击新创建的<code>li</code>元素，并没有输出元素中的内容。</p>
<p>原因是：我们通过<code>querySelectorAll</code>方法获取所有<code>li</code>元素，但是通过这个方法不能实时对增加的事件进行绑定。也就是说无法完成对新元素事件的绑定。</p>
<p>解决办法：先创建新元素，然后在进行事件的绑定。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">bindEvent</span>(<span class="params"></span>) &#123;</span><br><span class="line">       <span class="keyword">var</span> children = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; children.<span class="property">length</span>; i++) &#123;</span><br><span class="line">         children[i].<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">           <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">innerHTML</span>);</span><br><span class="line">         &#125;);</span><br><span class="line">       &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;#btn&quot;</span>);</span><br><span class="line">     <span class="keyword">var</span> ul = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;ul&quot;</span>);</span><br><span class="line">     btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">       <span class="comment">//创建li</span></span><br><span class="line">       <span class="keyword">var</span> newLi = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">       <span class="keyword">var</span> newText = <span class="variable language_">document</span>.<span class="title function_">createTextNode</span>(<span class="string">&quot;a6&quot;</span>);</span><br><span class="line">       newLi.<span class="title function_">appendChild</span>(newText);</span><br><span class="line">       <span class="comment">//把创建的li添加到ul上</span></span><br><span class="line">       ul.<span class="title function_">appendChild</span>(newLi);</span><br><span class="line">       <span class="comment">//重新添加事件处理程序</span></span><br><span class="line">       <span class="title function_">bindEvent</span>();</span><br><span class="line">     &#125;);</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们创建了一个<code>bindEvent</code>函数，把对<code>li</code>元素添加事件的操作封装到了该方法中。</p>
<p>然后在按钮对应的事件处理函数中，先完成新元素的创建，然后在调用<code>bindEvent</code>方法，完成对<code>li</code>元素事件的绑定操作。</p>
<p>虽然以上完成了我们的需求，但是还有一个问题需要解决，就是我们前面所讲的：由于给每个<code>li</code>元素都添加了单击事件，导致占用内存比较多，性能比较低，所以可以使用事件委托的方式来改造上面的程序。</p>
<p>改造后的程序如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> ul = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;ul&quot;</span>);</span><br><span class="line">      <span class="comment">//   var parent = document.querySelector(&quot;ul&quot;);</span></span><br><span class="line">      ul.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> target = e.<span class="property">target</span>;</span><br><span class="line">        <span class="keyword">if</span> (target.<span class="property">nodeName</span>.<span class="title function_">toLowerCase</span>() === <span class="string">&quot;li&quot;</span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(target.<span class="property">innerHTML</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;#btn&quot;</span>);</span><br><span class="line"></span><br><span class="line">      btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">//创建li</span></span><br><span class="line">        <span class="keyword">var</span> newLi = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">        <span class="keyword">var</span> newText = <span class="variable language_">document</span>.<span class="title function_">createTextNode</span>(<span class="string">&quot;a6&quot;</span>);</span><br><span class="line">        newLi.<span class="title function_">appendChild</span>(newText);</span><br><span class="line">        <span class="comment">//把创建的li添加到ul上</span></span><br><span class="line">        ul.<span class="title function_">appendChild</span>(newLi);</span><br><span class="line">        <span class="comment">//重新添加事件处理程序</span></span><br><span class="line">        <span class="comment">// bindEvent();</span></span><br><span class="line">      &#125;);</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们通过<code>querySelector</code>方法获取<code>ul</code>这个父元素，然后给该元素添加单击事件，在对应的事件处理程序中，判断获取到的元素是否为<code>li</code>，如果是打印<code>li</code>元素中的内容。</p>
<p>由于这里我们没有在使用<code>querySelectorAll</code>函数，所以这里我们也没有必要在封装到一个函数中了。</p>
<p>关于按钮的单击事件的处理，没有任何的变化。</p>
<p>以上我们就是通过事件委托的方式，给父元素添加了事件，对应的子元素都具有了相应的事件，这样的处理方式性能更高。</p>
<p>关于事件委托，在这里我们就介绍完了，通过前面的讲解，希望对事件委托有一个比较深刻的理解。</p>
<p>在<code>JavaScript</code>中还有一些其它的比较常用的事件，例如：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">焦点相关的事件:focus,blur等事件</span><br><span class="line">鼠标相关的事件:mouseover,mouseout等事件</span><br><span class="line">键盘相关的事件：keydown,keyup,keypress等</span><br><span class="line">其它事件...</span><br></pre></td></tr></table></figure>

<p>关于这些事件，大家可以查看相应的文档，了解对应的基本使用。</p>
<h2 id="13、介绍一下浏览器的重排与重绘"><a href="#13、介绍一下浏览器的重排与重绘" class="headerlink" title="13、介绍一下浏览器的重排与重绘"></a>13、介绍一下浏览器的重排与重绘</h2><p>在前面的课程中，我们也提到过对<code>DOM</code>的操作是比较消耗性能的，这是因为它会带来浏览器的重绘与重排。</p>
<p>在讲解什么是重排与重绘之前,先来说一下浏览器渲染<code>HTML</code>的过程。</p>
<p>浏览器渲染<code>HTML</code>的过程大体上可以分为4步</p>
<p>第一：<code>HTML</code>代码被<code>HTML</code>解析器解析成对应的<code>DOM</code>树，<code>CSS</code>代码被<code>CSS</code>解析器解析成对应的样式规则集。</p>
<p>第二：<code>DOM</code>树与<code>CSS</code>解析完成后，附加在一起形成一个渲染树</p>
<p>第三：节点信息的计算，即根据渲染树计算出每个节点的几何信息（宽，高等信息）</p>
<p>第四：渲染绘制，根据计算完成的节点信息绘制整个页面。</p>
<p>而我们所要讲解的重排与重绘就发生在第三步和第四步中。</p>
<p><strong>什么是重排</strong></p>
<p>当对一个<code>DOM</code>节点信息进行修改的时候，需要对该<code>DOM</code>结构进行重新的计算。并且该<code>DOM</code>结构的修改会决定周边<code>DOM</code>结构的更改范围，主要分为全局范围和局部范围。</p>
<p>全局范围就是从页面的根节点<code>html</code>标签开始，对整个渲染树进行重新计算，例如：我们修改窗口的尺寸或者修改了根元素的字体大小的时，都会导致对整个渲染树进行重新计算。</p>
<p>局部范围只会对渲染树的某部分进行重新计算。例如要改变页面中某个<code>div</code>的宽度，只需要重新计算渲染树中与该<code>div</code>相关的内容就可以了。</p>
<p>而重排的过程发生在<code>DOM</code>节点信息修改的时候，重排实际是根据渲染树中每个渲染对象的信息，计算出各自渲染对象的几何信息，例如<code>DOM</code>元素的位置，尺寸，大小等。然后将其放在页面中的正确的位置上。</p>
<p>综上所述，我们明白了重排其实就是一种改变页面布局的操作。那么常见的引起重排的操作有哪些呢？</p>
<p>（1）页面首次渲染</p>
<p>在页面首次渲染的时候，<code>HTML</code>页面中的各个元素位置，尺寸，大小等信息都是未知的，需要通过与<code>css</code>样式规则集才能够确定出各个元素的几何信息。这个过程中会产生很多元素集合信息的计算，所以会产生重排。</p>
<p>(2)浏览器窗口大小的改变</p>
<p>页面渲染完成后，就会得到一个固定的渲染树。如果此时对浏览器窗口进行缩放或者是拉伸操作，渲染树中从根元素<code>html</code>标签开始的所有元素，都会重新计算其几何信息，从而产生重排的操作。</p>
<p>(3)元素位置改变和尺寸的改变</p>
<p>(4)元素内容改变,例如，文本内容被另外一个不同尺寸的图片替换。</p>
<p>(5)添加或者删除可见的DOM元素</p>
<p>(6)获取某些特定的属性</p>
<p>当我们对<code>javascript</code>某些操作属性的修改也会导致重排的操作，而频繁的重排操作会对浏览器引擎产生很大的消耗。所以浏览器不会对<code>js</code>的每个操作都进行一次重排，而是维护一个会引起重排操作的队列，等到队列中的操作达到了一定的数量或者是到了一定的时间间隔的时候，浏览器才会去刷新一次队列，进行真正的重排操作。</p>
<p>虽然浏览器有这样的优化，但是我们写的一些代码还会导致浏览器提取刷新队列，例如以下的操作。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">offsetLeft,offsetWidth,offsetHeight,offsetTop</span><br><span class="line">scrollTop,scrollLeft,scrollWidth,scrollHeight</span><br><span class="line">clientTop,clientLeft,clientWidth,clientHeight</span><br><span class="line">widht,height</span><br></pre></td></tr></table></figure>

<p>当我们进行以上属性操作的时候，浏览器为了返回最精确的信息，需要刷新队列，因为队列中的某些操作会影响到这些属性值的获取。</p>
<p>以上就是浏览器重排的介绍</p>
<p><strong>浏览器重绘</strong></p>
<p>浏览器的重绘指的就是改变元素在页面中的展示样式，而不会引起元素在文档中位置的改变。例如：改变元素的颜色，背景色，透明度等。</p>
<p>常见的引起重绘的操作如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="attr">color</span>:颜色</span><br><span class="line">border-<span class="attr">style</span>:边框样式</span><br><span class="line"><span class="attr">visibility</span>: 元素是否可见</span><br><span class="line"><span class="attr">background</span>:背景样式，包括背景颜色，背景图片等</span><br><span class="line">text-<span class="attr">decoration</span>:文本下划线，上划线等</span><br><span class="line">border-<span class="attr">radius</span>:边框圆角</span><br><span class="line">box-<span class="attr">shadow</span>:元素的阴影</span><br></pre></td></tr></table></figure>

<p>以上就是浏览器的重绘的介绍。</p>
<p>通过对浏览器重排与重绘的介绍，相信大家已经有所了解了，那么它们两者之间有什么关系呢？</p>
<p>简单的说，重排一定会引起重绘，而重绘却不一定会引起重排的操作。</p>
<p>因为当元素在重排的过程中，元素的位置等几何信息会重新计算，并会引起元素的重新渲染，这样就会产生重绘的操作，而在重绘的时候，只是改变了元素的展示的样式，而不会引起元素在文档中位置的改变，所以一般不会引起重排的操作。</p>
<p><strong>性能优化</strong></p>
<p>浏览器的重排与重绘是比较消耗性能的，所以我们应该尽量减少重排与重绘的操作，这也是优化网页性能的一种方式。</p>
<p>常见的方法如下：</p>
<p>第一：将样式属性值的修改合并为一次。</p>
<p>例如，我们需要修改一个元素的样式，可以通过如下的代码实现：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> mainDiv = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>);</span><br><span class="line">    mainDiv.<span class="property">style</span>.<span class="property">width</span> = <span class="string">&quot;200px&quot;</span>;</span><br><span class="line">    mainDiv.<span class="property">style</span>.<span class="property">height</span> = <span class="string">&quot;100px&quot;</span>;</span><br><span class="line">    mainDiv.<span class="property">style</span>.<span class="property">background</span> = <span class="string">&quot;#ccc&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>但是问题是，在上面的操作中多次修改了<code>style</code>属性，会引发多次的重排与重绘操作。</p>
<p>所以为了解决这个问题，可以将这些样式合并在一个<code>class</code>类中。</p>
<figure class="highlight css"><table><tr><td class="code"><pre><span class="line">&lt;style&gt;</span><br><span class="line">    <span class="selector-class">.changeStyle</span> &#123;</span><br><span class="line">      <span class="attribute">width</span>: <span class="number">200px</span>;</span><br><span class="line">      <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line">      <span class="attribute">background</span>: <span class="string">&quot;#ccc&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &lt;/style&gt;</span><br></pre></td></tr></table></figure>

<p>然后通过通过<code>javascript</code>直接修改元素的样式</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;div1&quot;</span>).<span class="property">className</span> = <span class="string">&quot;changeStyle&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>这样我们可以在最后一步完成样式的修改，从而只引起一次的重排与重绘的操作。</p>
<p>第二：</p>
<p>将需要多次重排的元素，<code>position</code>属性设为<code>absolute</code>或<code>fixed</code>，这样此元素就脱离了文档流，它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。</p>
<p>第三：在对多节点操作的时候，可以现在内测中完成，然后在添加到文档中。</p>
<p>如下代码所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">createTable</span>(<span class="params">list</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> table = $(<span class="string">&quot;#table&quot;</span>);</span><br><span class="line">      <span class="keyword">var</span> rowHtml = <span class="string">&quot;&quot;</span>;</span><br><span class="line">      list.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">        rowHtml += <span class="string">&quot;&lt;tr&gt;&quot;</span>;</span><br><span class="line">        rowHtml += <span class="string">&quot;&lt;td&gt;&quot;</span> + item.<span class="property">userName</span> + <span class="string">&quot;&lt;/td&gt;&quot;</span>;</span><br><span class="line">        rowHtml += <span class="string">&quot;&lt;td&gt;&quot;</span> + item.<span class="property">userPwd</span> + <span class="string">&quot;&lt;/td&gt;&quot;</span>;</span><br><span class="line">        rowHtml += <span class="string">&quot;&lt;/tr&gt;&quot;</span>;</span><br><span class="line">        table.<span class="title function_">append</span>(rowHtml);</span><br><span class="line">        rowHtml = <span class="string">&quot;&quot;</span>;</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>当调用<code>createTable</code>方法的时候，会从<code>list</code>集合中取出一条数据，然后放在<code>tr</code>标签中，紧跟着添加到表格中，这样就会导致每添加一行数据，都会引发一次浏览器的重排和重绘的操作，如果数据很多，则会对渲染造成很大的影响。</p>
<p>修改后的代码</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">createTabel</span>(<span class="params">list</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> table = $(<span class="string">&quot;#table&quot;</span>);</span><br><span class="line">        <span class="keyword">var</span> rowHtml = <span class="string">&quot;&quot;</span>;</span><br><span class="line">        list.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">item</span>) &#123;</span><br><span class="line">          rowHtml += <span class="string">&quot;&lt;tr&gt;&quot;</span>;</span><br><span class="line">          rowHtml += <span class="string">&quot;&lt;td&gt;&quot;</span> + item.<span class="property">userName</span> + <span class="string">&quot;&lt;/td&gt;&quot;</span>;</span><br><span class="line">          rowHtml += <span class="string">&quot;&lt;td&gt;&quot;</span> + item.<span class="property">userPwd</span> + <span class="string">&quot;&lt;/td&gt;&quot;</span>;</span><br><span class="line">          rowHtml += <span class="string">&quot;&lt;/tr&gt;&quot;</span>;</span><br><span class="line">        &#125;);</span><br><span class="line">    <span class="comment">//将数据一次性追加到表格中，完成一次渲染</span></span><br><span class="line">        table.<span class="title function_">append</span>(rowHtml);</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>通过上面的改造以后，只会引起一次浏览器的重绘与重排的操作，从而带来很大的新能提升。</p>
<p>第四：由于<code>display</code>属性为<code>none</code>的元素不在渲染树中，对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时，可以先隐藏它，操作完成后再显示。这样只在隐藏和显示时触发两次重排。</p>
<p>第五：　尽量减少<code>table</code>布局,随便修改一个单元格的高度或宽度都会让整个表格进行重排，性能非常差。</p>
<p>第六：在对多个同级元素做事件绑定的时候，推荐使用事件委托机制来处理。</p>
<p>第七：文档片段<code>DocumentFragment</code>的使用，关于这块内容，在前面的课程中已经使用过。</p>
<p>使用批量插入元素，例如：向页面的<code>ul</code>元素中添加<code>100</code>个<code>li</code>元素，</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> listNode = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">      <span class="comment">//创建一个文档片段，文档片段存在于内存中，并不在DOM树中，所以此时还没有插入到DOM中</span></span><br><span class="line">      <span class="comment">//也就是先将dom插入到临时区域中</span></span><br><span class="line">      <span class="keyword">const</span> frag = <span class="variable language_">document</span>.<span class="title function_">createDocumentFragment</span>();</span><br><span class="line">      <span class="comment">//执行插入</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">const</span> li = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;li&quot;</span>);</span><br><span class="line">        li.<span class="property">innerHTML</span> = <span class="string">`item<span class="subst">$&#123;i&#125;</span>`</span>;</span><br><span class="line">        frag.<span class="title function_">appendChild</span>(li);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//都完成后，再插入到DOM树中</span></span><br><span class="line">      listNode.<span class="title function_">appendChild</span>(frag);</span><br></pre></td></tr></table></figure>

<p>以上就是关于浏览器重绘与重排的内容。</p>
<h1 id="六、AJAX"><a href="#六、AJAX" class="headerlink" title="六、AJAX"></a>六、AJAX</h1><h2 id="1、什么是AJAX"><a href="#1、什么是AJAX" class="headerlink" title="1、什么是AJAX"></a>1、什么是AJAX</h2><p>Ajax是一种异步请求数据的web开发技术，对于改善用户的体验和页面性能很有帮助。简单地说，在不需要重新刷新页面的情况下，Ajax 通过异步请求加载后台数据，并在网页上呈现出来。常见运用场景有表单验证是否登入成功、百度搜索下拉框提示和快递单号查询等等。</p>
<p><strong>Ajax的目的是提高用户体验，较少网络数据的传输量</strong>。同时，由于AJAX请求获取的是数据而不是<code>html</code>文档，因此它也节省了网络带宽，让互联网用户的网络冲浪体验变得更加顺畅。</p>
<p>关于提高用户的体验，可以通过下面来进行体会</p>
<p>下图是普通的请求方式</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/ajax1.png"></p>
<p>下图是<code>ajax</code>请求的方式</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/ajax2.png"></p>
<h2 id="2、AJAX原理是什么"><a href="#2、AJAX原理是什么" class="headerlink" title="2、AJAX原理是什么"></a>2、AJAX原理是什么</h2><p><code>Ajax</code>相当于在用户和服务器之间加了一个中间层,使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器，像一些数据验证和数据处理等都交给Ajax引擎自己来做，只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。</p>
<p>Ajax的原理简单来说通过<code>XmlHttpRequest</code>对象来向服务器发送异步请求，从服务器获得数据，然后用JavaScript来操作DOM而更新页面。</p>
<p><code>XMLHttpRequest</code>是<code>ajax</code>的核心机制，它是在<code>IE5</code>中首先引入的，是一种支持异步请求的技术。简单的说，也就是JavaScript可以及时向服务器提出请求和处理响应，而不阻塞用户。达到无刷新的效果。</p>
<h2 id="3、AJAX基本的使用"><a href="#3、AJAX基本的使用" class="headerlink" title="3、AJAX基本的使用"></a>3、AJAX基本的使用</h2><p>这里主要掌握的是能够手动创建<code>AJAX</code>.</p>
<p>创建步骤：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/AJAX%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B.png"></p>
<p>创建<code>xhr</code>对象</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> xhr = <span class="literal">null</span>;</span><br><span class="line"><span class="keyword">if</span> (<span class="variable language_">window</span>.<span class="property">XMLHttpRequest</span>) &#123;<span class="comment">// 兼容 IE7+, Firefox, Chrome, Opera, Safari  </span></span><br><span class="line">    xhr = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();  </span><br><span class="line">&#125; <span class="keyword">else</span> &#123;<span class="comment">// 兼容 IE6, IE5 </span></span><br><span class="line">    xhr = <span class="keyword">new</span> <span class="title class_">ActiveXObject</span>(<span class="string">&quot;Microsoft.XMLHTTP&quot;</span>);  </span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure>

<p>配置请求地址与发送请求</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">xhr.<span class="title function_">open</span>(method, url, <span class="keyword">async</span>);  </span><br><span class="line"><span class="title function_">send</span>(string);<span class="comment">//`POST`请求时才使用字符串参数，否则不用带参数。</span></span><br><span class="line"><span class="comment">// method：请求的类型；GET 或 POST</span></span><br><span class="line"><span class="comment">// url：文件在服务器上的位置</span></span><br><span class="line"><span class="comment">// async：true（异步）或 false（同步）</span></span><br></pre></td></tr></table></figure>

<p><strong>注意：POST请求一定要设置请求头的格式内容</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">xhr.<span class="title function_">open</span>(<span class="string">&quot;POST&quot;</span>, <span class="string">&quot;test.html&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">xhr.<span class="title function_">setRequestHeader</span>(<span class="string">&quot;Content-type&quot;</span>, <span class="string">&quot;application/x-www-form-urlencoded&quot;</span>);  </span><br><span class="line">xhr.<span class="title function_">send</span>(<span class="string">&quot;fname=Henry&amp;lname=Ford&quot;</span>);  <span class="comment">//`POST`请求参数放在send里面，即请求体</span></span><br></pre></td></tr></table></figure>

<p>处理响应</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">xhr.<span class="property">onreadystatechange</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123; </span><br><span class="line">    <span class="keyword">if</span> (xhr.<span class="property">readyState</span> == <span class="number">4</span> &amp;&amp; xhr.<span class="property">status</span> == <span class="number">200</span>)&#123;    </span><br><span class="line">    <span class="variable language_">document</span>.<span class="title class_">GetElementById</span>(<span class="string">&quot;mydiv&quot;</span>).<span class="property">innerHTML</span> = xhr.<span class="property">responseText</span>;  </span><br><span class="line">    &#125;</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure>

<h5 id="什么是readyState？"><a href="#什么是readyState？" class="headerlink" title="什么是readyState？"></a>什么是readyState？</h5><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">readyState是XMLHttpRequest对象的一个属性，用来标识当前XMLHttpRequest对象处于什么状态。</span><br><span class="line">readyState总共有5个状态值，分别为0~4，每个值代表了不同的含义：</span><br><span class="line"></span><br><span class="line">0：未初始化 — 尚未调用.open()方法；</span><br><span class="line">1：启动 — 已经调用.open()方法，但尚未调用.send()方法；</span><br><span class="line">2：发送 — 已经调用.send()方法，但尚未接收到响应；</span><br><span class="line">3：接收 — 已经接收到部分响应数据；</span><br><span class="line">4：完成 — 已经接收到全部响应数据，而且已经可以在客户端使用了；</span><br></pre></td></tr></table></figure>

<h5 id="什么是status？"><a href="#什么是status？" class="headerlink" title="什么是status？"></a>什么是status？</h5><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">HTTP状态码(status)由三个十进制数字组成。HTTP状态码共分为5种类型：</span><br><span class="line"></span><br><span class="line">1xx（临时响应）：表示临时响应并需要请求者继续执行操作的状态码。</span><br><span class="line">2xx（成功）：表示成功处理了请求的状态码。</span><br><span class="line">3xx（重定向）：表示要完成请求，需要进一步操作。通常，这些状态代码用来重定向。</span><br><span class="line">4xx（请求错误）：这些状态码表示请求可能出错，妨碍了服务器的处理。</span><br><span class="line">5xx（服务器错误）：这些状态码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误，而不是请求出错。</span><br></pre></td></tr></table></figure>

<h2 id="4、AJAX优缺点分析"><a href="#4、AJAX优缺点分析" class="headerlink" title="4、AJAX优缺点分析"></a>4、AJAX优缺点分析</h2><p><strong>优点</strong></p>
<p>(1)无刷新更新数据</p>
<p><code>AJAX</code>最大的优点是在不需要刷新浏览器的情况下，能够与服务器保持通信，并且能够减少不必要的数据数据传输，降低网络数据流量，这样可以加快响应用户的请求，避免不必要的等待时间，提高用户的体验。</p>
<p>(2)前后端分离</p>
<p>前端人员只关注前端页面逻辑的开发，通过<code>ajax</code>获取后端数据然后进行展示处理，而后端专注于请求的获取，响应的处理，职责明确。</p>
<p><strong>缺点：</strong></p>
<p>(1) 破坏浏览器的后退功能</p>
<p>浏览器有一个比较重要的功能就是历史记录的功能，通过后退按钮可以后退到浏览器之前访问的页面，但是使用了<code>ajax</code>后无法后退，也就是破坏了浏览器的后退机制。</p>
<p>（2）不利于搜索引擎的优化</p>
<p>百度，谷歌在进行搜索引擎优化的时候(<code>SEO</code>),会获取页面中的内容，而通过<code>ajax</code>请求返回的数据是通过<code>javascript</code>动态添加到页面上的，而百度等搜索引擎无法抓取到这些通过<code>javascript</code>动态生成的内容，所以不利于<code>SEO</code></p>
<p>(3) 破坏了<code>URL</code>统一资源定位的功能。</p>
<p>由于<code>AJAX</code>的请求并不会修改浏览器中地址栏的<code>URL</code>，因此对于相同的<code>URL</code>，不同的用户看到的内容是不一样的，例如，你访问某个电商网站，在该电商网站中搜索到一件非常好的商品，你现在把地址发给你的同学，而你的同学打开这个地址后，却看不到这件商品。</p>
<p>所以网站的搜索的实现，一般不是通过<code>ajax</code>来发送请求。</p>
<h2 id="5、Get和Post请求数据的区别"><a href="#5、Get和Post请求数据的区别" class="headerlink" title="5、Get和Post请求数据的区别"></a>5、Get和Post请求数据的区别</h2><p>(1)参数传递</p>
<p><code>get</code>请求会将参数添加到<code>URL</code>地址的后面，在调用<code>ajax</code>的<code>send</code>方法的时候，传递的参数是<code>null</code>，即<code>xhr.send()</code>;</p>
<p><code>post</code>请求的数据会放在请求体中，用户是无法通过<code>URL</code>地址直接看到的，调用<code>send</code>方法的时候，需要指定要发送到服务端的数据，即<code>xhr.send(data)</code></p>
<p>(2)服务端的处理</p>
<p>针对<code>get</code>请求与<code>post</code>请求，在服务端的处理也是不一样的。如果以<code>Express</code>来作为服务端，<code>get</code>的请求需要通过<code>Request.query</code>来获取参数，而<code>post</code>请求的处理，需要通过<code>Request.body</code>来获取数据。</p>
<p>（3）传递的数据量</p>
<p><code>get</code>请求的数据量小，对于不同的浏览器是有差异 ，谷歌浏览器限制<code>8k</code>.<code>post</code>请求传递的数据量比较大，一般默认不受限制。但是服务器一般会做限制。</p>
<p>（4）安全性</p>
<p><code>get</code>请求的安全性比较低，因为请求的数据会出现在<code>url</code>上，通过浏览器的缓存或者是历史记录很容易获取到请求的数据。<code>post</code>请求是将数据放在请求体中进行传递，数据不会出现在<code>URL</code>，安全性比较高。</p>
<h2 id="6、Get和Post请求的应用场景"><a href="#6、Get和Post请求的应用场景" class="headerlink" title="6、Get和Post请求的应用场景"></a>6、Get和Post请求的应用场景</h2><p>在了解了<code>get</code>方式和<code>post</code>请求方式的区别以后，下面看一下它们的应用场景。</p>
<p><code>get</code>的应用场景</p>
<p>（1）数据的搜索，单击搜索按钮，搜索网站中指定的数据。</p>
<p>  (2) 传递的数据量小，适合用于<code>url</code>方式进行传递</p>
<p> (3) 数据安全性要求不高的情况</p>
<p><code>post</code>请求的应用场景</p>
<p>(1) 传递数据量比较大的情况，例如上传文件</p>
<p>(2) 表单提交，例如用户登录，注册，要求数据安全性比较高的情况。</p>
<p>(3) 请求会修改数据库中数据的情况，例如，添加数据，修改数据等。</p>
<h2 id="7、浏览器同源策略"><a href="#7、浏览器同源策略" class="headerlink" title="7、浏览器同源策略"></a>7、浏览器同源策略</h2><p>浏览器同源策略是浏览器最基本也是最核心的安全功能，它规定客户端脚本在没有明确授权的情况下，不能读写不同源的目标资源。</p>
<p>所谓的同源指的是相同协议，域名和端口号，如果两个资源路径在协议，域名，端口号上有任何一点不同，则它们就不属于同源的资源，</p>
<p>另外在同源策略上，又分为两种表现形式：</p>
<p>第一：禁止对不同页面进行<code>DOM</code>操作</p>
<p>第二：禁止使用<code>XMLHttpRequest</code>向不是同源的服务器发送<code>ajax</code>请求。</p>
<h2 id="8、为什么浏览器会有跨域限制的问题？"><a href="#8、为什么浏览器会有跨域限制的问题？" class="headerlink" title="8、为什么浏览器会有跨域限制的问题？"></a>8、为什么浏览器会有跨域限制的问题？</h2><p>什么是跨域呢？</p>
<p>访问同源的资源是被浏览器允许的，但是如果访问不同源的资源，浏览器默认是不允许的。访问不同源的资源那就是我们所说的跨域。</p>
<p>如下表格所示：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E8%B7%A8%E5%9F%9F.png"></p>
<p>从表中可以看出域名，子域名，端口号，协议不同都属于不同源，当脚本被认为是来至不同源时，均被浏览器拒绝请求。</p>
<p>浏览器对跨域访问的限制，可以在很大的程度上保护用户数据的安全。</p>
<p>第一：假如没有<code>Dom</code>同源策略的限制，就有可能会出现如下的安全隐患</p>
<p>黑客做了一个假的的网站，通过<code>iframe</code>嵌套了一个银行的网站，然后把<code>iframe</code>的高度宽度调整到占据浏览器的可视区域 ，这样用户进入这个假的网站后，看到就是和真正的银行网站是一样的内容。如果用户输入了用户名和密码，这个假的网站就可以跨域访问到所嵌套的银行网站的<code>DOM</code>节点，从而黑客就可以获取到用户输入的用户名和密码了。</p>
<p>第二：如果浏览器没有<code>XMLHttpRequest</code>同源策略限制，黑客可以进行跨站请求伪造(<code>CSRF</code>)攻击，具体方式如下：</p>
<p>(1)用户登录了个人银行页面<code>A</code>,页面<code>A</code>会在<code>Cookie</code>中保存用户信息</p>
<p>(2)后来用户又访问了一个恶意的页面<code>B</code>,在该页面中执行了恶意<code>Ajax</code>请求的代码</p>
<p>(3)这时页面<code>B</code>会向页面<code>A</code>发送<code>Ajax</code>请求，该请求会默认发送用户<code>Cookie</code>信息。</p>
<p>(4)页面<code>A</code>会从请求的<code>Cookie</code>中获取用户信息，验证无误后，就会返回用户的一系列相关的数据，而这些数据就会被恶意的页面B所获取，从而造成用户数据的泄漏。</p>
<p>正是存在这些危险的场景存在，所以同源策略的限制就显得非常总要。</p>
<h2 id="9、跨域问题演示"><a href="#9、跨域问题演示" class="headerlink" title="9、跨域问题演示"></a>9、跨域问题演示</h2><p>创建一个文件夹，在该文件夹中创建<code>index.html</code>文件，该文件中的代码如下：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btnLogin&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="title function_">sendRequest</span>();</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">function</span> <span class="title function_">sendRequest</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> userName = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;userName&quot;</span>).<span class="property">value</span>;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//这里为了简单，暂时不考虑浏览器兼容性问题</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> xhr = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">let</span> url = <span class="string">&quot;http://localhost:3000/getUserNameInfo?name=&quot;</span> + userName;</span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="title function_">open</span>(<span class="string">&quot;get&quot;</span>, url, <span class="literal">true</span>);</span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="title function_">send</span>();</span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="property">onreadystatechange</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="keyword">if</span> (xhr.<span class="property">readyState</span> === <span class="number">4</span> &amp;&amp; xhr.<span class="property">status</span> === <span class="number">200</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">console</span>.<span class="title function_">log</span>(xhr.<span class="property">responseText</span>);</span></span><br><span class="line"><span class="language-javascript">          &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;;</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    用户名:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btnLogin&quot;</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在该文件夹下面安装<code>express</code></p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">npm install express</span><br></pre></td></tr></table></figure>

<p>同时创建<code>server.js</code>文件，该文件的代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/getUserNameInfo&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> userName = req.<span class="property">query</span>.<span class="property">name</span>;</span><br><span class="line">    <span class="keyword">var</span> result = &#123;</span><br><span class="line">        <span class="attr">id</span>: <span class="number">10001</span>,</span><br><span class="line">        <span class="attr">userName</span>: userName,</span><br><span class="line">        <span class="attr">userAge</span>:<span class="number">21</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">var</span> data = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(result);</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123; <span class="string">&#x27;Content-type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span> &#125;)</span><br><span class="line">    res.<span class="title function_">write</span>(data);</span><br><span class="line">    res.<span class="title function_">end</span>()</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;服务端启动....&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>下面启动服务端</p>
<p>同时<code>index.html</code>文件也通过<code>vscode</code>自带的服务器进行访问。</p>
<p>这时会出现如下错误：</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Access to XMLHttpRequest at &#x27;http://localhost:3000/getUserNameInfo?name=admin&#x27; from origin &#x27;http://127.0.0.1:5500&#x27; has been blocked by CORS policy: No &#x27;Access-Control-Allow-Origin&#x27; header is present on the requested resource.</span><br></pre></td></tr></table></figure>

<p>通过以上错误可以发现，现在的程序出现 跨域的问题，</p>
<p>下面看一下具体的解决方案</p>
<h2 id="10、CORS"><a href="#10、CORS" class="headerlink" title="10、CORS"></a>10、CORS</h2><p>通过上面的错误，我们明白了，客户端不能发送跨域请求是因为服务端并不接收跨域的请求，所以为了解决跨域请求的问题，我们可以将服务端设置为可以接收跨域请求。</p>
<p>这里我们需要使用<code>CORS</code>(‘跨域资源共享’),来解决跨域请求的问题。<code>CORS</code>主要的实现方式是服务端通过对响应头的设置，接收跨域请求的处理。</p>
<p>服务端修改后的代码如下：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;*&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="comment">//设置可以接收请求的域名</span></span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>, <span class="string">&#x27;http://127.0.0.1:5500&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Methods&#x27;</span>, <span class="string">&#x27;GET, POST,PUT&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Headers&#x27;</span>, <span class="string">&#x27;Content-Type&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Content-Type&#x27;</span>, <span class="string">&#x27;application/json;charset=utf-8&#x27;</span>);</span><br><span class="line">    req.<span class="title function_">next</span>();</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/getUserNameInfo&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> userName = req.<span class="property">query</span>.<span class="property">name</span>;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;userName=&#x27;</span>,userName)</span><br><span class="line">    <span class="keyword">var</span> result = &#123;</span><br><span class="line">        <span class="attr">id</span>: <span class="number">10001</span>,</span><br><span class="line">        <span class="attr">userName</span>: userName,</span><br><span class="line">        <span class="attr">userAge</span>:<span class="number">21</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">var</span> data = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(result);</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123; <span class="string">&#x27;Content-type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span> &#125;)</span><br><span class="line">    res.<span class="title function_">write</span>(data);</span><br><span class="line">    res.<span class="title function_">end</span>()</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;服务端启动....&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在原有的代码中，我们主要是添加了如下的代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;*&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="comment">//设置可以接收请求的域名</span></span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>, <span class="string">&#x27;http://127.0.0.1:5500&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Methods&#x27;</span>, <span class="string">&#x27;GET, POST,PUT&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Access-Control-Allow-Headers&#x27;</span>, <span class="string">&#x27;Content-Type&#x27;</span>);</span><br><span class="line">    res.<span class="title function_">header</span>(<span class="string">&#x27;Content-Type&#x27;</span>, <span class="string">&#x27;application/json;charset=utf-8&#x27;</span>);</span><br><span class="line">    req.<span class="title function_">next</span>();</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，最主要的是<code>  res.header(&#39;Access-Control-Allow-Origin&#39;, &#39;http://127.0.0.1:5500&#39;);</code>这行代码，</p>
<p>这行代码是必须的，表示服务器可以接收哪个域发送的请求，可以用通配符<code>*</code>，表示接收全部的域，但是为了安全，我们最好设置特定的域。我们这里测试的是<code>http://127.0.0.1:5500</code>(注意：如果客户端地址是<code>127.0.0.1</code>,这里不能写成<code>localhost</code>,同时还需要注意，这里地址最后没有<code>/</code>)</p>
<p>后面请求头信息可以根据情况进行选择设置，例如接收请求的方法，数据传输的格式等。</p>
<p>通过对服务端的处理不会对前端代码做任何的处理，但是由于不同系统服务端采用的语言与框架是不同的，所以导致服务端的处理方式不同。</p>
<h2 id="11、JSONP"><a href="#11、JSONP" class="headerlink" title="11、JSONP"></a>11、JSONP</h2><p><code>JSONP</code>是客户端与服务端进行跨域通信比较常用的解决办法，它的特点是简单，兼容老式浏览器，并且对服务器影响小。</p>
<p><code>JSONP</code>的实现的实现思想可以分为两步：</p>
<p>第一：在网页中动态添加一个<code>script</code>标签，通过<code>script</code>标签向服务器发送请求，在请求中会携带一个请求的<code>callback</code>回调函数名。</p>
<p>第二:  服务器在接收到请求后，会进行相应处理，然后将参数放在<code>callback</code>回调函数中对应的位置，并将<code>callback</code>回调函数通过<code>json</code>格式进行返回。</p>
<p>前端代码：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;btnLogin&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        btn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="title function_">sendRequest</span>();</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">      &#125;;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">function</span> <span class="title function_">sendRequest</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> userName = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;userName&quot;</span>).<span class="property">value</span>;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//请求参数，其中包含回调函数</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> param = <span class="string">&quot;name=&quot;</span> + userName + <span class="string">&quot;&amp;callback=successFn&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//请求的url</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> url = <span class="string">&quot;http://localhost:3000/getUserNameInfo?&quot;</span> + param;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> script = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;script&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        script.<span class="property">src</span> = url;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(script);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">function</span> <span class="title function_">successFn</span>(<span class="params">result</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;result=&quot;</span>, result);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   function sendRequest() &#123;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     var userName = document.getElementById(&quot;userName&quot;).value;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     //这里为了简单，暂时不考虑浏览器兼容性问题</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     var xhr = new XMLHttpRequest();</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     let url = &quot;http://localhost:3000/getUserNameInfo?name=&quot; + userName;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     xhr.open(&quot;get&quot;, url, true);</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     xhr.send();</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     xhr.onreadystatechange = function () &#123;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//       if (xhr.readyState === 4 &amp;&amp; xhr.status === 200) &#123;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//         console.log(xhr.responseText);</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//       &#125;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//     &#125;;</span></span></span><br><span class="line"><span class="language-javascript">      <span class="comment">//   &#125;</span></span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    用户名:<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userName&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btnLogin&quot;</span>&gt;</span>登录<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们重新改造了<code>sendRequest</code>方法，在该方法中构建了<code>param</code>参数，该参数的内容包括了用户输入的用户名以及回调函数名。下面构建好所要请求的服务端的<code>url</code>地址，将该<code>url</code>地址交给<code>script</code>标签的<code>src</code>属性，通过该属性向服务器发送请求。</p>
<p>同时定义回调函数<code>successFn</code>,接收服务端返回的数据。可以对服务端返回的数据做进一步的处理。</p>
<p>这里需要注意的一点就是：回调函数必须设置为全局的函数。因为服务端返回响应后，会在全局环境下查找回调函数。</p>
<p>下面看一下服务端的处理：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line"><span class="comment">// app.all(&#x27;*&#x27;, function (req, res) &#123;</span></span><br><span class="line"><span class="comment">//     //设置可以接收请求的域名</span></span><br><span class="line"><span class="comment">//     res.header(&#x27;Access-Control-Allow-Origin&#x27;, &#x27;http://127.0.0.1:5500&#x27;);</span></span><br><span class="line"><span class="comment">//     res.header(&#x27;Access-Control-Allow-Methods&#x27;, &#x27;GET, POST,PUT&#x27;);</span></span><br><span class="line"><span class="comment">//     res.header(&#x27;Access-Control-Allow-Headers&#x27;, &#x27;Content-Type&#x27;);</span></span><br><span class="line"><span class="comment">//     res.header(&#x27;Content-Type&#x27;, &#x27;application/json;charset=utf-8&#x27;);</span></span><br><span class="line"><span class="comment">//     req.next();</span></span><br><span class="line"><span class="comment">// &#125;)</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/getUserNameInfo&#x27;</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> userName = req.<span class="property">query</span>.<span class="property">name</span>;</span><br><span class="line">    <span class="comment">//获取请求的回调函数</span></span><br><span class="line">    <span class="keyword">var</span> callbackFn = req.<span class="property">query</span>.<span class="property">callback</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;callbackFn==&#x27;</span>,callbackFn)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;userName=&#x27;</span>,userName)</span><br><span class="line">    <span class="keyword">var</span> result = &#123;</span><br><span class="line">        <span class="attr">id</span>: <span class="number">10001</span>,</span><br><span class="line">        <span class="attr">userName</span>: userName,</span><br><span class="line">        <span class="attr">userAge</span>:<span class="number">21</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">var</span> data = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(result);</span><br><span class="line">    res.<span class="title function_">writeHead</span>(<span class="number">200</span>, &#123; <span class="string">&#x27;Content-type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span> &#125;)</span><br><span class="line">    <span class="comment">//返回值是对对回调函数的调用</span></span><br><span class="line">    res.<span class="title function_">write</span>(callbackFn+<span class="string">&#x27;(&#x27;</span>+data+<span class="string">&#x27;)&#x27;</span>)</span><br><span class="line">    <span class="comment">// res.write(data);</span></span><br><span class="line">    res.<span class="title function_">end</span>()</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;服务端启动....&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在服务的代码中，需要接收回调函数的名称。</p>
<p>同时返回的内容中，包含了回调函数的名称，以及传递给该回调函数的具体数据。</p>
<p>这样当回调函数返回给浏览器后，浏览器可以从全局的环境中查找该回调函数，并进行执行。</p>
<p>使用<code>JSONP</code>的优点与缺点：</p>
<p>优点：</p>
<p>简单，不存在浏览器兼容性的问题</p>
<p>缺点：</p>
<p>只能实现<code>get</code>请求，如果是<code>post</code>请求则无法进行跨域的处理。</p>
<h1 id="七、ES6"><a href="#七、ES6" class="headerlink" title="七、ES6"></a>七、ES6</h1><p>从这一章节开始，我们来看一下关于<code>ES6</code>的重点内容。</p>
<h2 id="1、let-关键字"><a href="#1、let-关键字" class="headerlink" title="1、let 关键字"></a>1、let 关键字</h2><h3 id="1-1-基本用法"><a href="#1-1-基本用法" class="headerlink" title="1.1 基本用法"></a>1.1 基本用法</h3><p>ES6中新增了let命令，用于变量的声明，基本的用法和var类似。例如：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">       <span class="comment">// 使用var使用声明变量</span></span><br><span class="line">       <span class="keyword">var</span> userName = <span class="string">&quot;bxg&quot;</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;userName=&quot;</span>, userName);</span><br><span class="line">       <span class="comment">// 使用let声明变量</span></span><br><span class="line">       <span class="keyword">let</span> userAge = <span class="number">18</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;userAge=&quot;</span>, userAge);</span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，我们发现var和let的基本使用是类似的，但是两者还是有本质的区别，最大的区别就是：</p>
<p>使用let所声明的变量只在let命令所在的代码块中有效。</p>
<h3 id="1-2-let与var区别"><a href="#1-2-let与var区别" class="headerlink" title="1.2 let与var区别"></a>1.2 let与var区别</h3><p>下面我们通过一个for循环的案例来演示一下let和var的区别,如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;i=&quot;</span>, i)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;last=&quot;</span>, i)</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，我们知道在循环体中i的值输出的是1–10，最后i的值为11.</p>
<p>但是如果将var换成let会出现什么问题呢？代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;i=&quot;</span>, i)</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;last=&quot;</span>, i)</span><br></pre></td></tr></table></figure>

<p>在循环体中输出的i的值还是1–10,但是循环体外部打印i的值时出现了错误，错误如下：</p>
<p><img src= "" data-lazy-src="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/let%E5%85%B3%E9%94%AE%E5%AD%97.png"></p>
<p><strong>出错的原因是：通过let声明的变量只在其对应的代码块中起作用，所谓的代码块我们可以理解成就是循环中的这一对大括号。</strong></p>
<p>当然在这里我们通过这个提示信息，可以发现在ES6中默认是启动了严格模式的，严格模式的特征就是：变量未声明不能使用，否则报的错误就是变量未定义。</p>
<p>那么在ES5中怎样开启严格模式呢？我们可以在代码的最开始加上：<strong>“use strict”</strong></p>
<p>刚才我们说到，let声明的变量只在代码块中起作用，其实就是说明了通过let声明的变量仅在<strong>块级作用域</strong>内有效</p>
<h3 id="1-3-块级作用域"><a href="#1-3-块级作用域" class="headerlink" title="1.3 块级作用域"></a>1.3 块级作用域</h3><h4 id="1-3-1-什么是块级作用域？"><a href="#1-3-1-什么是块级作用域？" class="headerlink" title="1.3.1 什么是块级作用域？"></a>1.3.1 什么是块级作用域？</h4><p>​		在这里告诉大家一个最简单的方法: <strong>有一段代码是用大括号包裹起来的，那么大括号里面就是一个块级作用域</strong></p>
<p>也就是说，在我们写的如下的案例中：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;i=&quot;</span>, i)</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;last=&quot;</span>, i)</span><br></pre></td></tr></table></figure>

<p>i 这个变量的作用域只在这一对大括号内有效，超出这一对大括号就无效了。</p>
<h4 id="1-3-2-为什么需要块级作用域？"><a href="#1-3-2-为什么需要块级作用域？" class="headerlink" title="1.3.2  为什么需要块级作用域？"></a>1.3.2  为什么需要块级作用域？</h4><p>​		ES5 只有全局作用域和函数作用域，没有块级作用域，这样就会带来一些问题，</p>
<pre><code>     第一：内层变量可能会覆盖外层变量
</code></pre>
<p>​                代码如下：		</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> temp = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">     <span class="keyword">function</span> <span class="title function_">show</span>(<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;temp=&quot;</span>, temp)</span><br><span class="line">         <span class="keyword">if</span> (<span class="literal">false</span>) &#123;</span><br><span class="line">             <span class="keyword">var</span> temp = <span class="string">&quot;hello world&quot;</span>;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">show</span>();</span><br></pre></td></tr></table></figure>

<p>执行上面的代码，输出的结果为 <em>temp&#x3D;undefined</em>  ，原因就是变量由于提升导致内层的temp变量覆盖了外层的temp变量</p>
<p>​		第二： 用来计数的循环变量成为了全局变量</p>
<p>​		关于这一点，在前面的循环案例中，已经能够看到。在这里，可以再看一下	</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;i=&quot;</span>, i)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;last=&quot;</span>, i)</span><br><span class="line">    &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，变量i的作用只是用来控制循环，但是循环结束后，它并没有消失，而是成了全局的变量，这不是我们希望的，我们希望在循环结束后，该变量就要消失。</p>
<p>以上两点就是，在没有块级作用域的时候，带来的问题。</p>
<p>下面使用let来改造前面的案例。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> temp = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">show</span>(<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;temp=&quot;</span>, temp)</span><br><span class="line">          <span class="keyword">if</span> (<span class="literal">false</span>) &#123;</span><br><span class="line">              <span class="keyword">let</span> temp = <span class="string">&quot;hello world&quot;</span>;</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">show</span>();</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以知道let不像var那样会发生“变量提升”的现象。</p>
<p>第二个问题前面已经讲解过。</p>
<h4 id="1-3-3-ES6块级作用域"><a href="#1-3-3-ES6块级作用域" class="headerlink" title="1.3.3 ES6块级作用域"></a>1.3.3 ES6块级作用域</h4><p>let实际上为JavaScript新增了块级作用域，下面再看几个案例，通过这几个案例，巩固一下关于“块级作用域”这个知识点的理解，同时进一步体会块级作用域带来的好处</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">      <span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">let</span> num = <span class="number">5</span>;</span><br><span class="line">          <span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">              <span class="keyword">let</span> num = <span class="number">10</span>;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">test</span>()</span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>上面的函数中有两个代码块，都声明了变量num,但是输出的结果是5.这表示外层的代码不受内层代码块的影响。如果使用var定义变量num,最后的输出的值就是10.</p>
<p>说一下，下面程序的输出结果是多少？</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> b = <span class="number">20</span>;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(b)</span><br><span class="line">            <span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                <span class="keyword">let</span> c = <span class="number">30</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(c);</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

<p>输出的结果是：b的值是20，在输出c的时候，出现了错误。</p>
<p>导致的原因，两个if就是两个块级作用域，c这个变量在第二个if中，也就是第二个块级作用域中，所以在外部块级作用域中无法获取到变量c.</p>
<p> 块级作用域的出现，带来了一个好处以前获得广泛使用的立即执行匿名函数不再需要了。</p>
<p>下面首先定义了一个立即执行匿名函数：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">;(<span class="keyword">function</span> <span class="title function_">text</span>(<span class="params"></span>) &#123;</span><br><span class="line">         <span class="keyword">var</span> temp = <span class="string">&#x27;hello world&#x27;</span>;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;temp=&#x27;</span>, temp);</span><br><span class="line">     &#125;)()</span><br></pre></td></tr></table></figure>

<p>匿名函数的好处：通过定义一个匿名函数，创建了一个新的函数作用域，相当于创建了一个“私有”的空间，该空间内的变量和方法，不会破坏污染全局的空间 。</p>
<p>但是以上的写法是比较麻烦的，有了“块级作用域”后就编的比较简单了，代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">       <span class="keyword">let</span> temp = <span class="string">&#x27;hello world&#x27;</span>;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;temp=&#x27;</span>, temp);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>通过以上的写法，也是创建了一个“私有”的空间，也就是创建了一个封闭的作用域。同样在该封闭的作用域中的变量和方法，不会破坏污染全局的空间。</p>
<p>但是以上写法比立即执行匿名函数简单很多。</p>
<p>现在问你一个问题，以下代码是否可以：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> temp = <span class="string">&#x27;你好&#x27;</span>;</span><br><span class="line">       &#123;</span><br><span class="line">            <span class="keyword">let</span> temp = <span class="string">&#x27;hello world&#x27;</span>;</span><br><span class="line">       &#125;</span><br></pre></td></tr></table></figure>

<p>答案是可以的，因为这里有两个“块级作用域”，一个是外层，一个是内层，互不影响。</p>
<p>但是，现在修改成如下的写法：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> temp = <span class="string">&#x27;你好&#x27;</span>;</span><br><span class="line">   &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;temp=&#x27;</span>, temp);</span><br><span class="line">      <span class="keyword">let</span> temp = <span class="string">&#x27;hello world&#x27;</span>;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>出错了，也是变量未定义的错误，造成错误的原因还是前面所讲解的let 不存在“变量提升”。</p>
<p>块级作用域还带来了另外一个好处，我们通过以下的案例来体会一下：</p>
<p>该案例希望不同时间打印变量i的值。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">          <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">              <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;i=&#x27;</span>, i);</span><br><span class="line">          &#125;, <span class="number">1000</span>)</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>那么上面程序的执行结果是多少？</p>
<p>对了，输出的都是 i&#x3D;3</p>
<p>造成的原因就是i为全局的。</p>
<p>那么可以怎样解决呢？相信这一点对你来说很简单，在前面ES5课程中也讲过。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">          (<span class="keyword">function</span>(<span class="params">i</span>) &#123;</span><br><span class="line">              <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">                  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;i=&#x27;</span>, i);</span><br><span class="line">              &#125;, <span class="number">1000</span>)</span><br><span class="line">          &#125;)(i)</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>通过以上的代码其实就是通过自定义一个函数，生成了函数的作用域,i变量就不是全局的了。</p>
<p>这种使用方式很麻烦，有了let命令后，就变的非常的简单了。</p>
<p>代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">          <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">              <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;i=&#x27;</span>, i);</span><br><span class="line">          &#125;, <span class="number">1000</span>)</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<h3 id="1-4-let命令注意事项"><a href="#1-4-let命令注意事项" class="headerlink" title="1.4 let命令注意事项"></a>1.4 let命令注意事项</h3><h4 id="1-4-1-不存在变量提升"><a href="#1-4-1-不存在变量提升" class="headerlink" title="1.4.1 不存在变量提升"></a>1.4.1 不存在变量提升</h4><p>let不像var那样会发生“变量提升”现象。所以，变量一定要在声明后使用，否则会出错。</p>
<p>关于这一点，前面的课程也多次强调。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br><span class="line"><span class="keyword">let</span> num = <span class="number">2</span>;</span><br></pre></td></tr></table></figure>

<h4 id="1-4-2-暂时性死区"><a href="#1-4-2-暂时性死区" class="headerlink" title="1.4.2 暂时性死区"></a>1.4.2 暂时性死区</h4><p>什么是暂时性死区呢？</p>
<p>先来看一个案例：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> num = <span class="number">123</span>;</span><br><span class="line">      <span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">          num = <span class="number">666</span>;</span><br><span class="line">          <span class="keyword">let</span> num;</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure>

<p>上面的代码中存在全局的变量num,但是在块级作用域内使用了let又声明了一个局部的变量num,导致后面的num绑定到这个块级作用域，所以在let声明变量前，对num进行赋值操作会出错。</p>
<p>所以说，只要在块级作用域中存在let命令，它所声明的变量就被“绑定”在这个区域中，不会再受外部的影响。</p>
<p>关于这一点，ES6明确规定，<strong>如果在区域中存在let命令，那么在这个区域中通过let命令所声明的变量从一开始就生成了一个封闭的作用域，只要在声明变量前使用，就会出错</strong>。</p>
<p>所以说，<strong>所谓的“暂时性死区”指的就是，在代码块内，使用let命令声明变量之前，该变量都是不可用的。</strong></p>
<h4 id="1-4-3-不允许重复声明"><a href="#1-4-3-不允许重复声明" class="headerlink" title="1.4.3  不允许重复声明"></a>1.4.3  不允许重复声明</h4><p>let 不允许在相同的作用域内重复声明一个变量，</p>
<p>如果使用var声明变量是没有这个限制的。</p>
<p>如下面代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> num = <span class="number">12</span>;</span><br><span class="line">            <span class="keyword">var</span> num = <span class="number">20</span>;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title function_">test</span>()</span><br></pre></td></tr></table></figure>

<p>以上代码没有问题，但是如果将var换成let,就会出错。如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">           <span class="keyword">let</span> num = <span class="number">12</span>;</span><br><span class="line">           <span class="keyword">let</span> num = <span class="number">20</span>;</span><br><span class="line">           <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="title function_">test</span>()</span><br></pre></td></tr></table></figure>

<p>当然，以下的写法也是错误的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">          <span class="keyword">var</span> num = <span class="number">12</span>;</span><br><span class="line">          <span class="keyword">let</span> num = <span class="number">20</span>;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">test</span>()</span><br></pre></td></tr></table></figure>

<p>同时，还需要注意，不能在函数内部声明的变量与参数同名，如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">num</span>) &#123;</span><br><span class="line">         <span class="keyword">let</span> num = <span class="number">20</span>;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title function_">test</span>(<span class="number">30</span>)</span><br></pre></td></tr></table></figure>

<h2 id="2、const命令"><a href="#2、const命令" class="headerlink" title="2、const命令"></a>2、const命令</h2><h3 id="2-1-基本用法"><a href="#2-1-基本用法" class="headerlink" title="2.1 基本用法"></a>2.1 基本用法</h3><p>const用来声明常量，常量指的就是一旦声明，其值是不能被修改的。</p>
<p>这一点与变量是不一样的，而变量指的是在程序运行中，是可以改变的量。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> num = <span class="number">12</span>;</span><br><span class="line">      num = <span class="number">30</span>;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(num)</span><br></pre></td></tr></table></figure>

<p>以上的代码输出结果为:30</p>
<p>但是通过const命令声明的常量，其值是不允许被修改的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line"><span class="variable constant_">PI</span> = <span class="number">3.15</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>)</span><br></pre></td></tr></table></figure>

<p>以上代码会出错。</p>
<p>在以后的编程中，如果确定某个值后期不需要更改，就可以定义成常量，例如:PI,它的取值就是3.14，后面不会改变。所以可以将其定义为常量。</p>
<h3 id="2-2-const命令注意事项"><a href="#2-2-const命令注意事项" class="headerlink" title="2.2 const命令注意事项"></a>2.2 const命令注意事项</h3><h4 id="2-2-1-不存在常量提升"><a href="#2-2-1-不存在常量提升" class="headerlink" title="2.2.1 不存在常量提升"></a>2.2.1 不存在常量提升</h4><p>以下代码是错误的</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span></span><br></pre></td></tr></table></figure>

<h4 id="2-2-2-只在声明的块级作用域内有效"><a href="#2-2-2-只在声明的块级作用域内有效" class="headerlink" title="2.2.2 只在声明的块级作用域内有效"></a>2.2.2 只在声明的块级作用域内有效</h4><p>const命令的作用域与let命令相同：只在声明的块级作用域内有效</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>);</span><br></pre></td></tr></table></figure>

<p>以上代码会出错</p>
<h4 id="2-2-3-暂时性死区"><a href="#2-2-3-暂时性死区" class="headerlink" title="2.2.3 暂时性死区"></a>2.2.3 暂时性死区</h4><p>const命令与let指令一样，都有暂时性死区的问题，如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>);</span><br><span class="line">    <span class="keyword">const</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上代码会出错</p>
<h4 id="2-2-4-不允许重复声明"><a href="#2-2-4-不允许重复声明" class="headerlink" title="2.2.4 不允许重复声明"></a>2.2.4 不允许重复声明</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>);</span><br></pre></td></tr></table></figure>

<p>以上代码会出错</p>
<h4 id="2-2-5-常量声明必须赋值"><a href="#2-2-5-常量声明必须赋值" class="headerlink" title="2.2.5 常量声明必须赋值"></a>2.2.5 常量声明必须赋值</h4><p>使用const声明常量，必须立即进行初始化赋值，不能后面进行赋值。</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">PI</span>;</span><br><span class="line"><span class="variable constant_">PI</span> = <span class="number">3.14</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable constant_">PI</span>);</span><br></pre></td></tr></table></figure>

<p>以上代码会出错</p>
<h2 id="3、解构赋值"><a href="#3、解构赋值" class="headerlink" title="3、解构赋值"></a>3、解构赋值</h2><h3 id="3-1、数组解构赋值基本用法"><a href="#3-1、数组解构赋值基本用法" class="headerlink" title="3.1、数组解构赋值基本用法"></a>3.1、数组解构赋值基本用法</h3><p>所谓的解构赋值，就是从数组或者是对象中提取出对应的值，然后将提取的值赋值给变量。</p>
<p>首先通过一个案例，来看一下以前是怎样实现的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">    <span class="keyword">let</span> num1 = arr[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">let</span> num2 = arr[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">let</span> num3 = arr[<span class="number">2</span>];</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2, num3);</span><br></pre></td></tr></table></figure>

<p>在这里定义了一个数组arr,并且进行了初始化，下面紧跟着通过下标的方式获取数组中的值，然后赋值给对应的变量。</p>
<p>虽然这种方式可以实现，但是相对来说比较麻烦，ES6中提供了解构赋值的方式，代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">let</span> [num1, num2, num3] = arr;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2, num3);</span><br></pre></td></tr></table></figure>

<p>将arr数组中的值取出来分别赋值给了，num1,num2和num3.</p>
<p>通过观察，发现解构赋值等号两侧的结构是类似。</p>
<p>下面再看一个案例：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [&#123;</span><br><span class="line">               <span class="attr">userName</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">               <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">           &#125;,</span><br><span class="line">           [<span class="number">1</span>, <span class="number">3</span>], <span class="number">6</span></span><br><span class="line">       ];</span><br><span class="line">       <span class="keyword">let</span> [&#123;</span><br><span class="line">               userName,</span><br><span class="line">               age</span><br><span class="line">           &#125;,</span><br><span class="line">           [num1, num2], num3</span><br><span class="line">       ] = arr;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(userName, age, num1, num2, num3);</span><br></pre></td></tr></table></figure>

<p>定义了一个arr数组，并且进行了初始化，arr数组中有对象，数组和数值。</p>
<p>现在通过解构赋值的方式，将数组中的值取出来赋给对应的变量，所以等号左侧的结构和数组arr的结构是一样的。</p>
<p>但是，如果不想获取具体的值，而是获取arr数组存储的json对象，数组，那么应该怎样写呢？</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [&#123;</span><br><span class="line">              <span class="attr">userName</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">              <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">          &#125;,</span><br><span class="line">          [<span class="number">1</span>, <span class="number">3</span>], <span class="number">6</span></span><br><span class="line">      ];</span><br><span class="line">      <span class="keyword">let</span> [jsonResult, array, num] = arr;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(jsonResult, array, num);</span><br></pre></td></tr></table></figure>

<h3 id="3-2、注意事项"><a href="#3-2、注意事项" class="headerlink" title="3.2、注意事项"></a>3.2、注意事项</h3><h5 id="3-2-1-如果解析不成功，对应的值会为undefined"><a href="#3-2-1-如果解析不成功，对应的值会为undefined" class="headerlink" title="3.2.1  如果解析不成功，对应的值会为undefined."></a>3.2.1  如果解析不成功，对应的值会为undefined.</h5><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> [num1, num2] = [<span class="number">6</span>]</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2);</span><br></pre></td></tr></table></figure>

<p>以上的代码中，num1的值为6，num2的值为undefined.</p>
<h5 id="3-2-2-不完全解构的情况"><a href="#3-2-2-不完全解构的情况" class="headerlink" title="3.2.2  不完全解构的情况"></a>3.2.2  不完全解构的情况</h5><p>所谓的不完全解构，表示等号左边只匹配右边数组的一部分。</p>
<p>代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> [num1, num2] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2);</span><br></pre></td></tr></table></figure>

<p>以上代码的执行结果：num1&#x3D;1,num2 &#x3D; 2</p>
<p>也就是只取了数组中的前两个值。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">     <span class="comment">// 如果只取第一个值呢？</span></span><br><span class="line">    <span class="keyword">let</span> [num1] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1);</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">//只取第二个值呢？</span></span><br><span class="line"><span class="keyword">let</span> [, num, ] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 只取第三个值呢？</span></span><br><span class="line"><span class="keyword">let</span> [, , num] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num);</span><br></pre></td></tr></table></figure>

<h3 id="3-4、对象解构赋值基本使用"><a href="#3-4、对象解构赋值基本使用" class="headerlink" title="3.4、对象解构赋值基本使用"></a>3.4、对象解构赋值基本使用</h3><p>解构不仅可以用于数组，还可以用于对象。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">         userName,</span><br><span class="line">         userAge</span><br><span class="line">     &#125; = &#123;</span><br><span class="line">         <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">         <span class="attr">userAge</span>: <span class="number">20</span></span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(userName, userAge);</span><br></pre></td></tr></table></figure>

<p>在对 对象进行解构赋值的时候，一定要注意：变量名必须与属性的名称一致，才能够取到正确的值。</p>
<p>如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    name,</span><br><span class="line">    age</span><br><span class="line">&#125; = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">    <span class="attr">userAge</span>: <span class="number">20</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(name, age);</span><br></pre></td></tr></table></figure>

<p>输出的结果都是undefined.</p>
<p>那么应该怎样解决上面的问题呢？</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">          <span class="attr">userName</span>: name,</span><br><span class="line">          <span class="attr">userAge</span>: age</span><br><span class="line">      &#125; = &#123;</span><br><span class="line">          <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">          <span class="attr">userAge</span>: <span class="number">20</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(name, age);</span><br></pre></td></tr></table></figure>

<p>通过以上的代码解决了对应的问题，那么这种方式的原理是什么呢？</p>
<p><strong>先找到同名属性，然后再赋值给对应的变量。</strong></p>
<p>把上面的代码，改造成如下的形式，更容易理解：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">    <span class="attr">userAge</span>: <span class="number">21</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    <span class="attr">userName</span>: name,</span><br><span class="line">    <span class="attr">userAge</span>: age</span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(name, age)</span><br></pre></td></tr></table></figure>

<p>如果按照ES5的方式：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> name = obj.<span class="property">userName</span></span><br><span class="line"><span class="keyword">let</span> age = obj.<span class="property">userAge</span></span><br></pre></td></tr></table></figure>

<h3 id="3-5、对象解构赋值注意事项"><a href="#3-5、对象解构赋值注意事项" class="headerlink" title="3.5、对象解构赋值注意事项"></a>3.5、对象解构赋值注意事项</h3><h4 id="3-5-1-默认解构"><a href="#3-5-1-默认解构" class="headerlink" title="3.5.1 默认解构"></a>3.5.1 默认解构</h4><p>所谓的默认解构，指的是取出来值就用取出来的值，如果取不出来就用默认的值。</p>
<p>演示默认解构之前，先来看如下的代码：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    name,</span><br><span class="line">    age</span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(name, age);</span><br></pre></td></tr></table></figure>

<p>你想一下输出结果是什么呢？</p>
<p>输出的结果是：zs  undefined</p>
<p>也就是name变量的值为:‘zs’, age变量的值为:’undefined’.</p>
<p>由于没有给age变量赋值所以该变量的值为’undefined’.</p>
<p>现在修改一下上面的程序</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    name,</span><br><span class="line">    age = <span class="number">20</span></span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(name, age);</span><br></pre></td></tr></table></figure>

<p>现在给age这个变量赋了一个默认值为20，所以输出的结果为：zs 20</p>
<p>这也就是刚才所说到的默认解构，也就是取出来值就用取出来的值，如果取不出来就用默认的值。</p>
<p>现在再问你一个问题：如果在对应中有age属性，那么对应的等号左侧的age这个变量的值是多少呢?</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">26</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    name,</span><br><span class="line">    age = <span class="number">20</span></span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(name, age);</span><br></pre></td></tr></table></figure>

<p>输出的结果为: zs  26</p>
<p>这就是，取出来值就用取出来的，取不出来就用默认值。</p>
<h4 id="3-5-2-嵌套结构对象的解构"><a href="#3-5-2-嵌套结构对象的解构" class="headerlink" title="3.5.2  嵌套结构对象的解构"></a>3.5.2  嵌套结构对象的解构</h4><p>解构也可以用于对嵌套结构的对象，如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">arr</span>: [</span><br><span class="line">        <span class="string">&quot;Hello&quot;</span>, &#123;</span><br><span class="line">            <span class="attr">msg</span>: <span class="string">&#x27;World&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    <span class="attr">arr</span>: [str, &#123;</span><br><span class="line">        msg</span><br><span class="line">    &#125;]</span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(str, msg);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中要注意的是：arr只是一种标志或者是一种模式，不是变量，因此不会被赋值。</p>
<p>再看一个案例:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">local</span>: &#123;</span><br><span class="line">        <span class="attr">start</span>: &#123;</span><br><span class="line">            <span class="attr">x</span>: <span class="number">20</span>,</span><br><span class="line">            <span class="attr">y</span>: <span class="number">30</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    <span class="attr">local</span>: &#123;</span><br><span class="line">        <span class="attr">start</span>: &#123;</span><br><span class="line">            x,</span><br><span class="line">            y</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125; = obj;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(x, y);</span><br></pre></td></tr></table></figure>

<p>在该案例中创建了一个obj对象，在该对象中又嵌套了一个local对象，该对象可以认为是一个表示位置的坐标对象，在该对象中又嵌套了一个start对象，start对象可以认为是一个位置的起始坐标点，所以在该对象中有两个属性为x,y，分别表示横坐标和纵坐标。</p>
<p>所以说obj对象是一个比较复杂的嵌套结构的对象，现在对该对象进行解构，那么在等号的左侧的结构要和obj对象的结构一致，最后输出打印x,y的值。</p>
<p>问题：如果现在要打印等号左侧的local和start，那么输出的结果是什么呢？</p>
<p>会出错，原因就是在等号的左侧，只有x和y是变量，local和start都是一种标识，一种模式，所以不会被赋值。</p>
<h3 id="3-6、字符串的解构赋值"><a href="#3-6、字符串的解构赋值" class="headerlink" title="3.6、字符串的解构赋值"></a>3.6、字符串的解构赋值</h3><p>字符串也可以进行解构赋值，这是因为字符串被转换成了一个类似于数组的对象。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> [a, b, c, d, e, f] = <span class="string">&#x27;itcast&#x27;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a, b, c, d, e, f);</span><br></pre></td></tr></table></figure>

<p>类似于数组的对象都有length属性，因此也可以对这个属性进行解构赋值。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    <span class="attr">length</span>: len</span><br><span class="line">&#125; = <span class="string">&#x27;itcast&#x27;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;len=&#x27;</span>, len);</span><br></pre></td></tr></table></figure>

<h3 id="3-7、函数参数的解构赋值"><a href="#3-7、函数参数的解构赋值" class="headerlink" title="3.7、函数参数的解构赋值"></a>3.7、函数参数的解构赋值</h3><p>函数的参数也能够进行解构的赋值，如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">[x, y]</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">test</span>([<span class="number">3</span>, <span class="number">6</span>]));</span><br></pre></td></tr></table></figure>

<p>上面的代码中，函数test的参数不是一个数组，而是通过解构得到的变量x和y.</p>
<p>函数的参数的解构也可以使用默认的值。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">&#123;</span></span><br><span class="line"><span class="params">    x = <span class="number">0</span>,</span></span><br><span class="line"><span class="params">    y = <span class="number">0</span></span></span><br><span class="line"><span class="params">&#125; = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> [x, y];</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">test</span>(&#123;</span><br><span class="line">    <span class="attr">x</span>: <span class="number">3</span>,</span><br><span class="line">    <span class="attr">y</span>: <span class="number">6</span></span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure>

<p>当然可以进行如下的调用</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="title function_">test</span>(&#123;<span class="attr">x</span>:<span class="number">3</span>&#125;)</span><br><span class="line"><span class="title function_">test</span>(&#123;&#125;)</span><br></pre></td></tr></table></figure>

<h3 id="3-8、解构赋值的好处"><a href="#3-8、解构赋值的好处" class="headerlink" title="3.8、解构赋值的好处"></a>3.8、解构赋值的好处</h3><h4 id="3-8-1-交换变量的值"><a href="#3-8-1-交换变量的值" class="headerlink" title="3.8.1 交换变量的值"></a>3.8.1 交换变量的值</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> num1 = <span class="number">3</span>;</span><br><span class="line"><span class="keyword">let</span> num2 = <span class="number">6</span>;</span><br><span class="line">[num1, num2] = [num2, num1];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2);</span><br></pre></td></tr></table></figure>

<h4 id="3-8-2-函数可以返回多个值"><a href="#3-8-2-函数可以返回多个值" class="headerlink" title="3.8.2 函数可以返回多个值"></a>3.8.2 函数可以返回多个值</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> [a, b, c] = <span class="title function_">test</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a, b, c);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，返回了三个值，当然在实际的开发过程中，你可以根据自己的实际情况确定返回的数据的个数。</p>
<p>如果，我只想接收返回中的一部分值呢？</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 接收第一个值</span></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> [a] = <span class="title function_">test</span>();</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 接收前两个值</span></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> [a, b] = <span class="title function_">test</span>();</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(a, b);</span><br><span class="line">        <span class="comment">// 只接收第一个值和第三个值。</span></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> [a, , b] = <span class="title function_">test</span>();</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(a, b);</span><br></pre></td></tr></table></figure>

<h4 id="3-8-3-函数返回一个对象"><a href="#3-8-3-函数返回一个对象" class="headerlink" title="3.8.3 函数返回一个对象"></a>3.8.3 函数返回一个对象</h4><p>可以将函数返回的多个值封装到一个对象中。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">num1</span>: <span class="number">3</span>,</span><br><span class="line">        <span class="attr">num2</span>: <span class="number">6</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    num1,</span><br><span class="line">    num2</span><br><span class="line">&#125; = <span class="title function_">test</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(num1, num2);</span><br></pre></td></tr></table></figure>

<h4 id="3-8-4-提取JSON对象中的数据"><a href="#3-8-4-提取JSON对象中的数据" class="headerlink" title="3.8.4 提取JSON对象中的数据"></a>3.8.4 提取JSON对象中的数据</h4><p>解构赋值对提取JSON对象中的数据也非常有用。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> userData = &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="number">12</span>,</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;zhangsan&#x27;</span>,</span><br><span class="line">    <span class="attr">userAge</span>: <span class="number">20</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> &#123;</span><br><span class="line">    id,</span><br><span class="line">    userName,</span><br><span class="line">    userAge</span><br><span class="line">&#125; = userData;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(id, userName, userAge);</span><br></pre></td></tr></table></figure>

<p>以上的代码可以快速提取JSON中的数据。</p>
<h2 id="4、扩展运算符与rest运算符"><a href="#4、扩展运算符与rest运算符" class="headerlink" title="4、扩展运算符与rest运算符"></a>4、扩展运算符与<code>rest</code>运算符</h2><h3 id="4-1-扩展运算符"><a href="#4-1-扩展运算符" class="headerlink" title="4.1 扩展运算符"></a>4.1 扩展运算符</h3><p>扩展运算符的表现形式是三个点（…）,可以将一个数组转换为用逗号分隔的序列。</p>
<p>下面通过一个案例看一下基本的应用，案例的要求是将两个数组合并为一个数组。</p>
<p>先采用传统的做法：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">let</span> arr2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line"><span class="keyword">let</span> arr3 = [].<span class="title function_">concat</span>(arr1, arr2);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr3);</span><br></pre></td></tr></table></figure>

<p>下面使用扩展运算符来完成上面的案例</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">let</span> arr2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line"><span class="keyword">let</span> arr3 = [...arr1, ...arr2];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr3);</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，发现也实现了我们最终想要的结果，<code>...arr1</code>是将 <code>arr1</code>这个数组中的所有的元素取出来，然后组成 ‘1,2,3’这个形式，放到 <code>...arr1</code>这个位置，同理arr2也是一样。</p>
<p>通过扩展运算符实现起来发现更加的简单。</p>
<p>当然我们可以将上面使用扩展运算符实现的案例，转成ES5看一下。</p>
<p>转成ES5的代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> arr1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">var</span> arr2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line"><span class="keyword">var</span> arr3 = [].<span class="title function_">concat</span>(arr1, arr2);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr3);</span><br></pre></td></tr></table></figure>

<p>发现和我们最开始实现的是一样的。</p>
<h3 id="4-2-扩展运算符应用场景"><a href="#4-2-扩展运算符应用场景" class="headerlink" title="4.2 扩展运算符应用场景"></a>4.2 扩展运算符应用场景</h3><h4 id="4-2-1-代替数组中的apply方法"><a href="#4-2-1-代替数组中的apply方法" class="headerlink" title="4.2.1 代替数组中的apply方法"></a>4.2.1 代替数组中的apply方法</h4><p>现在求数组中的最大值。</p>
<p>求最大值，我们想到的第一种方法就是：</p>
<p>通过循环的方式来完成，如下面的代码：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">12</span>, <span class="number">23</span>, <span class="number">11</span>, <span class="number">56</span>];</span><br><span class="line"><span class="keyword">let</span> max = arr[<span class="number">0</span>]</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index &lt; arr.<span class="property">length</span>; index++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (arr[index] &gt; max) &#123;</span><br><span class="line">        max = arr[index];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;max=&quot;</span>, max);</span><br></pre></td></tr></table></figure>

<p>这种方式非常麻烦，所以可以使用Math对象中的max方法来完成.</p>
<p>先来看一下Math.max的基本用法</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">1</span>, <span class="number">5</span>, <span class="number">12</span>, <span class="number">67</span>));</span><br></pre></td></tr></table></figure>

<p>如果是用Math.max来计算数组中的最大值。（ES5的写法）</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">12</span>, <span class="number">23</span>, <span class="number">11</span>, <span class="number">56</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="property">max</span>.<span class="title function_">apply</span>(<span class="literal">null</span>, arr));</span><br></pre></td></tr></table></figure>

<p>虽然可以使用<code>Math.max.apply</code>来实现，但是感觉还是很麻烦，</p>
<p>这里就可以使用扩展运算符</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">12</span>, <span class="number">23</span>, <span class="number">11</span>, <span class="number">56</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Math</span>.<span class="title function_">max</span>(...arr));</span><br><span class="line">	</span><br></pre></td></tr></table></figure>

<p>在上面的代码中（不管ES5还是ES6），由于JavaScript不提供求数组中最大值的函数，所以只能将数组转换成一个参数的列表，然后再进行相应的求值。</p>
<h4 id="4-2-2-用于函数调用"><a href="#4-2-2-用于函数调用" class="headerlink" title="4.2.2 用于函数调用"></a>4.2.2 用于函数调用</h4><p>在函数调用的时候，需要进行参数的传递，在某些情况下，通过扩展运算符，更有利于参数的传递。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">num1, num2</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> num1 + num2;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> array = [<span class="number">23</span>, <span class="number">56</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">test</span>(...array));</span><br></pre></td></tr></table></figure>

<p>通过扩展运算符，将array这个数组中的值取出来，然后23赋值给了num1,56赋值给了num2.</p>
<p>下面，再看一个使用扩展运算符处理函数参数的案例。</p>
<p>把一组数据添加到数组中。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">array, ...items</span>) &#123;</span><br><span class="line">    array.<span class="title function_">push</span>(...items);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(array)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> array = [<span class="number">23</span>, <span class="number">56</span>];</span><br><span class="line"><span class="title function_">test</span>(array, <span class="number">90</span>, <span class="number">78</span>, <span class="number">98</span>);</span><br></pre></td></tr></table></figure>

<p>test这个函数的作用是：把90,78,98这三个数添加到array这个数组中，</p>
<p>在这里要注意的是：90,78,98 这三个数据给了items这个参数，这里我们用到了后面所讲解的rest参数，所以items这个参数实际上是一个数组，然后在test这个函数体内，又通过扩展运算符将items这个数组中的数据取出来给了array这个数组。</p>
<h3 id="4-3-rest运算符"><a href="#4-3-rest运算符" class="headerlink" title="4.3 rest运算符"></a>4.3 <code>rest</code>运算符</h3><h4 id="4-3-1-rest参数基本使用"><a href="#4-3-1-rest参数基本使用" class="headerlink" title="4.3.1 rest参数基本使用"></a>4.3.1 rest参数基本使用</h4><p>在<code>ES6</code>中引入了rest参数，形式为”…变量名”，用于获取函数中的多余参数，这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">s, num1, num2</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> s + (num1 + num2);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">add</span>(<span class="string">&#x27;+&#x27;</span>, <span class="number">2</span>, <span class="number">3</span>));</span><br></pre></td></tr></table></figure>

<p>在上面定义的函数中，传递了三个参数，第一个参数：是一个‘+’号，后面两个参数，表示进行加法运算的数据。</p>
<p>但是，问题是如果参与运算的数据比较多，那么定义的参数也就比较多，这样比较麻烦。这时可以使用rest参数形式。</p>
<p>如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">...values</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(values);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">add</span>(<span class="number">2</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>

<p>通过以上的代码输出发现，values这个参数是一个数组，所传递的数据都存储到这个数组中，下面可以将数据从这个数组中取出来，进行运算。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">...values</span>) &#123;</span><br><span class="line">    <span class="comment">// console.log(values);</span></span><br><span class="line">    <span class="keyword">let</span> sum = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index &lt; values.<span class="property">length</span>; index++) &#123;</span><br><span class="line">        sum += values[index];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> sum;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">add</span>(<span class="number">2</span>, <span class="number">3</span>));</span><br></pre></td></tr></table></figure>

<p>上面的循环方式，使用的是传统的模式，也可以使用 <code>forEach</code>的形式来进行循环，如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">...values</span>) &#123;</span><br><span class="line">     <span class="keyword">let</span> sum = <span class="number">0</span>;</span><br><span class="line">     values.<span class="title function_">forEach</span>(<span class="keyword">function</span>(<span class="params">item</span>) &#123;</span><br><span class="line">         sum += item</span><br><span class="line">     &#125;)</span><br><span class="line">     <span class="keyword">return</span> sum;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">add</span>(<span class="number">2</span>, <span class="number">3</span>));</span><br></pre></td></tr></table></figure>
<p>下面我们再来看一个<code>rest</code>运算符的基本使用</p>
<p>解构会将相同数据结构对应的值赋给对应的变量，但是当我们想将其中的一部分值统一赋值给一个变量的时候，可以使用<code>rest</code>运算符。</p>
<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">    <span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">    <span class="keyword">let</span> [arr1, ...arr2] = arr; <span class="comment">//进行解构处理</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(arr1); <span class="comment">// 1</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(arr2); <span class="comment">// [2,3,4,5,6]</span></span><br><span class="line">  &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，<code>arr</code>经过解构后，变量<code>arr1</code>的值为1，而通过<code>rest</code>运算符会将后面所有的值都统一赋值给<code>arr2</code>变量，得到的<code>arr2</code>为一个数组。</p>
<h4 id="4-3-2-rest参数的好处"><a href="#4-3-2-rest参数的好处" class="headerlink" title="4.3.2 rest参数的好处"></a>4.3.2 rest参数的好处</h4><p>在以前的案例中，我们都是使用<code>arguments</code>.</p>
<p>那么这种用法比<code>arguments</code> 有什么样的好处呢？</p>
<p>对数据进行排序，使用的是 <code>arguments</code>。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sortFunc</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>).<span class="title function_">sort</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">sortFunc</span>(<span class="number">23</span>, <span class="number">12</span>, <span class="number">67</span>));</span><br></pre></td></tr></table></figure>

<p>下面使用 rest的方式</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">sortFunc</span>(<span class="params">...values</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> values.<span class="title function_">sort</span>()</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">sortFunc</span>(<span class="number">23</span>, <span class="number">12</span>, <span class="number">67</span>));</span><br></pre></td></tr></table></figure>

<p>因为values这个参数本身就是数组，所以可以直接使用sort函数，进行数据的排序操作。</p>
<p>通过以上的对比，发现使用rest这种参数的写法更简洁。</p>
<h4 id="4-3-3-rest参数注意问题"><a href="#4-3-3-rest参数注意问题" class="headerlink" title="4.3.3 rest参数注意问题"></a>4.3.3 rest参数注意问题</h4><p>在使用rest这种参数的时候，一定要注意： rest参数之后不能再有其他的参数，也就是说rest参数只能是最后一个参数，否则会报错。</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">a, ...b, c</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(a);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(b);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(c);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">test</span>(<span class="number">1</span>, <span class="number">23</span>, <span class="number">2</span>, <span class="number">5</span>);</span><br></pre></td></tr></table></figure>

<p>以上代码会出错，要求rest参数只能是最后一个参数。</p>
<p>通过前面对扩展运算符和<code>rest</code>运算符的讲解，我们知道两者是互为逆运算，扩展运算符是将数组分隔成独立的序列，而<code>rest</code>运算符是将独立的序列合并成一个数组。</p>
<p>既然两者都是通过3个点(…)来表示，那么如何判断这3个点属于哪一种运算符呢？我们可以遵循如下的规则：</p>
<p>第一：当3个点(…)出现在函数的形参上或者出现在赋值号的左侧，则表示的就是<code>rest</code>运算符</p>
<p>第二：当3个点(…)出现在函数的实参上或者出现在赋值号的右侧，则表示它为扩展运算符。</p>
<h2 id="5、什么是箭头函数"><a href="#5、什么是箭头函数" class="headerlink" title="5、什么是箭头函数"></a>5、什么是箭头函数</h2><h3 id="5-1-箭头函数基本使用"><a href="#5-1-箭头函数基本使用" class="headerlink" title="5.1 箭头函数基本使用"></a>5.1 箭头函数基本使用</h3><p>在ES6中允许使用 “箭头”（&#x3D;&gt;）来定义函数。</p>
<p>先使用传统的方式定义一个函数。</p>
<p>示例代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用传统方式定义函数</span></span><br><span class="line"><span class="keyword">let</span> f = <span class="keyword">function</span>(<span class="params">x, y</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">3</span>, <span class="number">6</span>));</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以发现传统方式来定义函数的时候，比较麻烦。</p>
<p>箭头函数的使用</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params">x, y</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> x + y</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">9</span>, <span class="number">8</span>));</span><br></pre></td></tr></table></figure>

<p>在调用f这个函数的时候，将9和8传递给了x,y这两个参数，然后进行加法运算。</p>
<p>如果参数只有一个，可以省略小括号。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = num =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> num / <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">6</span>));</span><br></pre></td></tr></table></figure>

<p>如果没有参数，只需要写一对小括号就可以。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">9</span> / <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>());</span><br></pre></td></tr></table></figure>

<p>上面我们写的代码中，发现函数体中只有一条语句，那么这时是可以省略大括号的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params">x, y</span>) =&gt; x + y;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">3</span>, <span class="number">6</span>));</span><br></pre></td></tr></table></figure>

<p>把上面的代码转换成ES5的写法，发现和我们前面写的代码是一样的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> f = <span class="keyword">function</span> <span class="title function_">f</span>(<span class="params">x, y</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">3</span>, <span class="number">6</span>));</span><br></pre></td></tr></table></figure>

<h3 id="5-2-箭头函数注意事项"><a href="#5-2-箭头函数注意事项" class="headerlink" title="5.2  箭头函数注意事项"></a>5.2  箭头函数注意事项</h3><h4 id="5-2-1-直接返回对象"><a href="#5-2-1-直接返回对象" class="headerlink" title="5.2.1 直接返回对象"></a>5.2.1 直接返回对象</h4><p>如果希望箭头函数<strong>直接</strong>返回一个对象，应该怎样写呢？</p>
<p>你可能认为很简单，可以采用如下的写法</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params">id, name</span>) =&gt; &#123;</span><br><span class="line">    <span class="attr">id</span>: id,</span><br><span class="line">    <span class="attr">userName</span>: name</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">1</span>, <span class="string">&#x27;zs&#x27;</span>));</span><br></pre></td></tr></table></figure>

<p>但是上面的写法是错误的，因为这时大括号被解释为代码块，解决的办法是：在对象外面加上小括号,</p>
<p>所以，正确的写法如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params">id, name</span>) =&gt; (&#123;</span><br><span class="line">    <span class="attr">id</span>: id,</span><br><span class="line">    <span class="attr">userName</span>: name</span><br><span class="line">&#125;);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">1</span>, <span class="string">&#x27;zs&#x27;</span>));</span><br></pre></td></tr></table></figure>

<p>通过打印，发现输出的是一个对象。</p>
<p>当然也可以采用如下的写法</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">f</span> = (<span class="params">id, name</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">id</span>: id,</span><br><span class="line">        <span class="attr">userName</span>: name</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">f</span>(<span class="number">1</span>, <span class="string">&#x27;zs&#x27;</span>));</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="5-2-2-箭头函数中this的问题"><a href="#5-2-2-箭头函数中this的问题" class="headerlink" title="5.2.2 箭头函数中this的问题"></a>5.2.2 箭头函数中this的问题</h4><p>下面定义一个对象，来理解this的应用。</p>
<p>看一下，如下代码：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">    <span class="title function_">getUserName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>();</span><br></pre></td></tr></table></figure>

<p>以上代码执行的结果为：’ls’,并且在该程序中<code>this</code> 为当前的person对象。</p>
<p>现在，将上面的代码修改一下，要求延迟1秒钟以后，再输出用户名的名称。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">    <span class="title function_">getUserName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>)</span><br><span class="line">        &#125;, <span class="number">1000</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>();</span><br></pre></td></tr></table></figure>

<p>上面的输出结果为：<code>undefined</code>，因为在setTimeout中this指的是window,而不是person对象。</p>
<p>为了解决上面的问题，可以将代码进行如下的修改：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;ls&#x27;</span>,</span><br><span class="line">    <span class="title function_">getUserName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> that = <span class="variable language_">this</span>;</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(that.<span class="property">userName</span>)</span><br><span class="line">        &#125;, <span class="number">1000</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>();</span><br></pre></td></tr></table></figure>

<p>在进入setTimeout这个方法之前，提前将this赋值给that变量，然后在setTimeout中使用that,那么这时that指的就是person对象。</p>
<p>上面的解决方法比较麻烦，可以修改成箭头函数的形式，代码如下所示：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;wangwu&#x27;</span>,</span><br><span class="line">    <span class="title function_">getUserName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">        &#125;,<span class="number">1000</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>();</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以发现在箭头函数中直接使用this是没有问题的。</p>
<p>你可以这样理解：<strong>在箭头函数中是没有this的，如果在箭头函数中使用了this,那么实际上使用的是外层代码块的this.  箭头函数不会创建自己的<code>this,它只会从自己的作用域链的上一层继承this</code></strong></p>
<p>或者通俗的理解：<strong>找出定义箭头函数的上下文（即包含箭头函数最近的函数或者是对象），那么上下文所处的父上下文即为this.</strong></p>
<p>那么在我们这个案例中，<code>setTimeout</code>函数中使用了箭头函数，箭头函数中用了<code>this,</code>而这时<code>this</code>指的是外层代码块也就是<code>person</code> ,所以箭头函数中使用的this指的就是<code>person</code>(包含箭头函数最近的函数是<code>setTimeout</code>,那么包含<code>setTimeout</code>这个函数的最近的函数或者是对象是谁呢？对了，是<code>getUserName</code>这个函数，而<code>getUserName</code>这个函数是属于哪个对象呢？是<code>person</code>,所以<code>this</code>为<code>person</code>)</p>
<p>下面，再看一个案例：（可以将下面的代码转换成ES5的代码）</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;zhangsan&#x27;</span>,</span><br><span class="line">    <span class="attr">getUserName</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>();</span><br></pre></td></tr></table></figure>

<p>输出结果为:undefined</p>
<p>因为这时包含<code>getUserName</code>这个箭头函数最近的对象是person(这里也就是说<code>getUserName</code>这个箭头函数的上下文为<code>person</code>),那么<code>person</code>对象所处的父上下文(也就是包含person这个对象最近的对象)，是谁呢？对了，就是<code>window</code>。</p>
<p>下面再看一个案例：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;zhangsan&#x27;</span>,</span><br><span class="line">    <span class="title function_">getUserName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">getUserName</span>()();</span><br></pre></td></tr></table></figure>

<p>根据上面总结的规律是，这段代码输出的结果是：’zhangsan’.</p>
<p>在这里还需要注意一个问题就是：</p>
<p>由于箭头函数没有自己的this,所以不能使用 <code>call()</code>、<code>apply()</code>、<code>bind()</code>这些方法来改变this的指向。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> adder = &#123;</span><br><span class="line">        <span class="attr">base</span>: <span class="number">1</span>,</span><br><span class="line"></span><br><span class="line">        <span class="attr">add</span>: <span class="keyword">function</span>(<span class="params">a</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> <span class="title function_">f</span> = v =&gt; v + <span class="variable language_">this</span>.<span class="property">base</span>;</span><br><span class="line">            <span class="keyword">let</span> b = &#123;</span><br><span class="line">                <span class="attr">base</span>: <span class="number">3</span></span><br><span class="line">            &#125;;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> f.<span class="title function_">call</span>(b, a);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(adder.<span class="title function_">add</span>(<span class="number">1</span>))</span><br></pre></td></tr></table></figure>

<p>上面代码执行的结果为:2</p>
<p>也就是说，箭头函数不能使用<code>call( )</code>来改变this的指向，本意是想让this指向b这个对象，但是实际上this还是adder这个对象。</p>
<h4 id="5-3-3-箭头函数不适合的场景"><a href="#5-3-3-箭头函数不适合的场景" class="headerlink" title="5.3.3 箭头函数不适合的场景"></a>5.3.3 箭头函数不适合的场景</h4><p>第一：不能作为构造函数，不能使用<code>new</code>操作符</p>
<p>构造函数是通过<code>new</code>操作符生成对象实例的，生成实例的过程也是通过构造函数给实例绑定<code>this</code>的过程，而箭头函数没有自己的<code>this</code>，因此不能使用箭头函数作为构造函数。</p>
<p>如下代码：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name</span>) &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>); <span class="comment">//正常</span></span><br></pre></td></tr></table></figure>

<p>以上是我们前面经常使用的一种方式，没有问题</p>
<p>下面看一下使用箭头函数作为构造函数的情况</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">Person</span> = (<span class="params">name</span>) =&gt; &#123;</span><br><span class="line">     <span class="variable language_">this</span>.<span class="property">userName</span> = name;</span><br><span class="line">   &#125;;</span><br><span class="line">   <span class="keyword">let</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;lisi&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>当执行上面的程序的时候，会出现错误</p>
<p>第二：没有<code>prototype</code>属性</p>
<p>因为在箭头函数中没有<code>this</code>,也就不存在自己的作用域，因此箭头函数是没有<code>prototype</code>属性的。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title function_">Person</span> = (<span class="params">name</span>) =&gt; &#123;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">userName</span> = name;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>); <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>

<p>第三：不适合将原型函数定义成箭头函数</p>
<p>在给构造函数添加原型函数时，如果使用箭头函数，其中的<code>this</code>会指向全局作用域<code>window</code>,而不会指向构造函数。</p>
<p>因此并不会访问到构造函数本身，也就无法访问到实例属性，失去了原型函数的意义。</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name</span>) &#123;</span><br><span class="line">       <span class="variable language_">this</span>.<span class="property">userName</span> = name;</span><br><span class="line">     &#125;</span><br><span class="line">     <span class="title class_">Person</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">sayHello</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>); <span class="comment">// window</span></span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">userName</span>); <span class="comment">// undefined</span></span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">let</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">     p.<span class="title function_">sayHello</span>();</span><br></pre></td></tr></table></figure>





<h2 id="6、对象的扩展"><a href="#6、对象的扩展" class="headerlink" title="6、对象的扩展"></a>6、对象的扩展</h2><h3 id="1、属性与方法的简洁表示方式"><a href="#1、属性与方法的简洁表示方式" class="headerlink" title="1、属性与方法的简洁表示方式"></a>1、属性与方法的简洁表示方式</h3><p>以前创建对象的方式：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> userName = <span class="string">&#x27;zhangsan&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> userAge = <span class="number">18</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">userName</span>: userName,</span><br><span class="line">    <span class="attr">userAge</span>: userAge</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person);</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以发现对象中的属性名和变量名是一样的，像这种情况，在ES6中是可以简化如下形式：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> userName = <span class="string">&#x27;zhangsan&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> userAge = <span class="number">18</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    userName,</span><br><span class="line">    userAge</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person);</span><br></pre></td></tr></table></figure>

<p>通过以上代码可以发现：在ES6中，如果对象的属性名和变量名是一样的，那么两者可以合二为一。</p>
<p>当然，除了属性可以简写，方法也可以简写，以前定义方法的形式如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> userName = <span class="string">&#x27;zhangsan&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> userAge = <span class="number">18</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    userName,</span><br><span class="line">    userAge,</span><br><span class="line">    <span class="attr">sayHello</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;你好&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">sayHello</span>();</span><br></pre></td></tr></table></figure>

<p>在ES6中可以简化成如下的形式:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> userName = <span class="string">&#x27;zhangsan&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> userAge = <span class="number">18</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    userName,</span><br><span class="line">    userAge,</span><br><span class="line">    <span class="title function_">sayHello</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Hello&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.<span class="title function_">sayHello</span>();</span><br></pre></td></tr></table></figure>

<p>所以在以后的编程中，会经常看到或者是用到这种<code>ES6</code>的表示形式。</p>
<h3 id="2、Object-assign-方法"><a href="#2、Object-assign-方法" class="headerlink" title="2、Object.assign( )方法"></a>2、Object.assign( )方法</h3><h4 id="2-1-基本使用"><a href="#2-1-基本使用" class="headerlink" title="2.1 基本使用"></a>2.1 基本使用</h4><p>现在，有一个需求，将一个对象的属性拷贝给另外一个对象，应该怎样处理？</p>
<p>你可能会说，很简单，可以通过循环的方式来来实现。</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj1 = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zhangsan&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> obj2 = &#123;</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> obj3 = &#123;&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj1) &#123;</span><br><span class="line">    obj3[key] = obj1[key];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> obj2) &#123;</span><br><span class="line">    obj3[key] = obj2[key];</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;obj3=&#x27;</span>, obj3);</span><br></pre></td></tr></table></figure>

<p>虽然通过循环的方式，可以实现对象属性的拷贝，但是很麻烦。下面讲解一个简单的方法：<code>Object.assign( )</code>方法.</p>
<p><code>Object.assign( )</code>方法用来源对象的所有可枚举的属性复制到目标对象。该方法至少需要两个对象作为参数，第一个参数是目标对象，后面的参数都是源对象。只要有一个参数不是对象，就会抛出异常。</p>
<p>示例代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> target = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">b</span>: <span class="number">2</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> source = &#123;</span><br><span class="line">    <span class="attr">c</span>: <span class="number">3</span>,</span><br><span class="line">    <span class="attr">d</span>: <span class="number">4</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(target, source);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(target);</span><br></pre></td></tr></table></figure>

<p>最终的结果：将source对象中的属性拷贝到target对象上。</p>
<p>在上面的定义中，可以看出参数不仅两个，可以有多个，但是要注意的是第一个参数一定是目标对象，下面再看一个多个参数的案例：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> target = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">b</span>: <span class="number">2</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> source = &#123;</span><br><span class="line">    <span class="attr">c</span>: <span class="number">3</span>,</span><br><span class="line">    <span class="attr">d</span>: <span class="number">4</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> source1 = &#123;</span><br><span class="line">    <span class="attr">e</span>: <span class="number">5</span>,</span><br><span class="line">    <span class="attr">f</span>: <span class="number">6</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(target, source, source1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(target);</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，将source和<code>source1</code>这两个对象的属性都拷贝给了target对象。</p>
<h4 id="2-2-深浅拷贝问题"><a href="#2-2-深浅拷贝问题" class="headerlink" title="2.2  深浅拷贝问题"></a>2.2  深浅拷贝问题</h4><p>通过<code>Object.assign( )</code>方法，实现的拷贝只拷贝了属性的值，属于浅拷贝。</p>
<p>如下代码所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj1 = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;张三&#x27;</span>,</span><br><span class="line">    <span class="attr">address</span>: &#123;</span><br><span class="line">        <span class="attr">city</span>: <span class="string">&#x27;北京&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> obj2 = &#123;&#125;;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(obj2, obj1);</span><br><span class="line">obj2.<span class="property">address</span>.<span class="property">city</span> = <span class="string">&quot;上海&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;obj1=&quot;</span>, obj1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;obj2=&quot;</span>, obj2);</span><br></pre></td></tr></table></figure>

<p>上面的代码中对<code>obj2</code>这个对象的city属性的值进行了修改，发现对应的<code>obj1</code>对象中的city属性的值也发生了改变。</p>
<p>但是，在某些情况下，我们不希望这样，我们希望修改一个对象的属性值时，不会影响到另外一个对象的属性值。</p>
<p>那么对应的要实现相应的深拷贝。</p>
<p>关于深拷贝，实现方式比较多，下面简单的说一种方式：(这里只是简单的模拟)</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params">source</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> newObj = &#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> key <span class="keyword">in</span> source) &#123;</span><br><span class="line">        <span class="comment">// 由于address属性为对象，所以执行递归。</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> source[key] === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">            newObj[key] = <span class="title function_">clone</span>(source[key]);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 如果是name属性直接赋值</span></span><br><span class="line">            newObj[key] = source[key];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> newObj;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> obj1 = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;张三&#x27;</span>,</span><br><span class="line">    <span class="attr">address</span>: &#123;</span><br><span class="line">        <span class="attr">city</span>: <span class="string">&#x27;北京&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> obj2 = <span class="title function_">clone</span>(obj1);</span><br><span class="line">obj2.<span class="property">address</span>.<span class="property">city</span> = <span class="string">&quot;上海&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;obj1=&quot;</span>, obj1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;obj2=&quot;</span>, obj2);</span><br></pre></td></tr></table></figure>



<h4 id="2-3-注意事项"><a href="#2-3-注意事项" class="headerlink" title="2.3 注意事项"></a>2.3 注意事项</h4><p>1、如果目标对象与源对象有同名属性，那么后面的属性会覆盖前面的属性。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> target = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="attr">b</span>: <span class="number">2</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> source = &#123;</span><br><span class="line">    <span class="attr">b</span>: <span class="number">3</span>,</span><br><span class="line">    <span class="attr">d</span>: <span class="number">4</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(target, source);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(target);</span><br></pre></td></tr></table></figure>

<p>上面的代码，将source对象中的属性拷贝给了target对象，但是source对象中有b这个属性，而且target对象上也有b属性，那么最终的结果是:source对象中的b属性覆盖掉target对象中的b属性。</p>
<p>2、不可枚举的属性不会被复制。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;&#125;;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(obj, <span class="string">&#x27;b&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">enumerable</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">value</span>: <span class="string">&#x27;world&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">let</span> obj1 = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="string">&#x27;hello&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(obj1, obj);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;obj1=&#x27;</span>, obj1);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，通过<code>Object.defineProperty()</code>方法为obj对象添加了一个属性b,这个属性的值为 ‘world’,并且指定了enumerable这个属性的值为false.也就是不可以被枚举。也就是该属性不可以通过for in来进行遍历。</p>
<p>最终，通过<code>Object.assign</code>这个方法进行拷贝，发现<code>obj1</code>对象中没有obj对象的b这个属性。</p>
<h2 id="7、Symbol"><a href="#7、Symbol" class="headerlink" title="7、Symbol"></a>7、Symbol</h2><h3 id="7-1、Symbol简介"><a href="#7-1、Symbol简介" class="headerlink" title="7.1、Symbol简介"></a>7.1、Symbol简介</h3><p>在具体讲解Symbol之前，先来看一个问题。</p>
<p><code>ES5</code>的对象属性名都是字符串，这样容易造成属性名的冲突。</p>
<p>代码如下所示：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">      <span class="attr">num</span>: <span class="number">10</span>,</span><br><span class="line">      <span class="string">&quot;num 1&quot;</span>: <span class="number">20</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">num</span>);</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(obj[<span class="string">&quot;num 1&quot;</span>]);</span><br></pre></td></tr></table></figure>

<p>通过以上的代码，可以发现在对象中定义的属性的名称本身就是字符串，而且发现“num 1”中间是有空格的，所以在访问该属性的时候，通过[ ]的形式来进行访问。</p>
<p>那么为什么说容易造成属性名的冲突呢？</p>
<p>举例说明：你用了一个别人提供的对象，但是又想为这个对象添加新的方法或者是属性，新方法或者是新属性的名称有可能与现有对象中的属性名称或者是方法的名称产生冲突。如果有一种机制，能够保证每个属性的名字都是唯一的，<strong>那么就能够从根本上防止属性名称的冲突问题</strong>。这也就是ES6引入Symbol的原因。</p>
<p>Symbol是一种数据类型，是JavaScript语言的第7种数据类型，前6种分别是:undefined,null,布尔值，字符串，数值和对象。</p>
<p>Symbol类型的值是通过Symbol函数生成的。它的值是独一无二的，也就是唯一的，可以保证对象中属性名称的唯一。</p>
<p>可以通过如下的代码测试类型</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">typeof</span> s);</span><br></pre></td></tr></table></figure>

<p>对应的输出类型为”symbol”</p>
<p>下面创建Symbol类型的变量，然后进行打印输出。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="keyword">let</span> s1 = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s1);</span><br></pre></td></tr></table></figure>

<p>发现输出的结果都是：Symbol( )。</p>
<p>输出的结果都是Symbol( ),那么无法区分，哪个Symbol( )是s变量的，哪个是s1变量的。</p>
<p>为了解决这个问题，Symbol( )函数可以接受一个字符串作为参数，这个参数表示对Symbol的描述，主要是为了在控制台进行输出打印的时候，能够区分开，Symbol最终是属于哪个变量的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="title class_">Symbol</span>(<span class="string">&#x27;s&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> s1 = <span class="title class_">Symbol</span>(<span class="string">&#x27;s1&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s1);</span><br></pre></td></tr></table></figure>

<p>输出的结果为：Symbol(s)和Symbol(s1)</p>
<p>注意：Symbol函数的参数只表示对当前Symbol值（结果）的描述，因此相同参数的Symbol函数的返回值是不相等的。代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="title class_">Symbol</span>(<span class="string">&#x27;s&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> s1 = <span class="title class_">Symbol</span>(<span class="string">&#x27;s&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s === s1);</span><br></pre></td></tr></table></figure>

<p>以上结果为：false.</p>
<h3 id="7-2、Symbol应用场景"><a href="#7-2、Symbol应用场景" class="headerlink" title="7.2、Symbol应用场景"></a>7.2、Symbol应用场景</h3><h4 id="7-2-1-作为属性名的Symbol"><a href="#7-2-1-作为属性名的Symbol" class="headerlink" title="7.2.1 作为属性名的Symbol"></a>7.2.1 作为属性名的Symbol</h4><p>在前面的课程中，讲解过由于Symbol的值是唯一的，并且能够保证对象中不会出现同名的属性。下面，先来讲解一下，怎样使用Symbol作为属性名，然后再看一下怎样保证对象中不会出现同名属性。</p>
<p>第一种添加属性的方式：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> mySymbol = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="keyword">let</span> obj = &#123;&#125;</span><br><span class="line">    <span class="comment">// 第一种添加属性的方式</span></span><br><span class="line">obj[mySymbol] = <span class="string">&#x27;hello&#x27;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj[mySymbol]);</span><br></pre></td></tr></table></figure>

<p>第二种添加属性的方式：</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> mySymbol = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    [mySymbol]: <span class="string">&#x27;world&#x27;</span> <span class="comment">// 注意mySymbol必须加上方括号，否则为字符串而不是Symbol类型。</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj[mySymbol]);</span><br></pre></td></tr></table></figure>

<p>第三种添加属性的方式</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> mySymbol = <span class="title class_">Symbol</span>();</span><br><span class="line"><span class="keyword">let</span> obj = &#123;&#125;;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(obj, mySymbol, &#123;</span><br><span class="line">    <span class="attr">value</span>: <span class="string">&#x27;你好&#x27;</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj[mySymbol]);</span><br></pre></td></tr></table></figure>

<h4 id="7-2-2-防止属性名称冲突"><a href="#7-2-2-防止属性名称冲突" class="headerlink" title="7.2.2  防止属性名称冲突"></a>7.2.2  防止属性名称冲突</h4><p>在前面，已经讲解了怎样使用Symbol作为属性名了，下面看一下怎样通过Symbol来防止属性名的冲突。</p>
<p>下面先定义一个对象，然后动态的向对象中添加一个id属性。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test1</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    obj.<span class="property">id</span> = <span class="number">42</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test2</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    obj.<span class="property">id</span> = <span class="number">369</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">test1</span>(obj);</span><br><span class="line"><span class="title function_">test2</span>(obj);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，有两个函数分别是test1和test2向obj这个对象中动态添加id属性，在这里可以把这两个函数想象成两个不同的模块，或者是两个不同开发人员来实现的功能。</p>
<p>但是问题是，由于test2( )这个函数后执行，所以会将test1( )这个函数创建的id属性的值覆盖掉。那么这是我们不希望看到的，为了解决这个问题，可以使用Symbol作为属性名来解决。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> mySymbol = <span class="title class_">Symbol</span>(<span class="string">&#x27;lib1&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test1</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    obj[mySymbol] = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> mySymbol2 = <span class="title class_">Symbol</span>(<span class="string">&#x27;lib2&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test2</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">    obj[mySymbol2] = <span class="number">369</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">test1</span>(obj);</span><br><span class="line"><span class="title function_">test2</span>(obj);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj);</span><br></pre></td></tr></table></figure>

<p>通过上面的代码可以发现，通过Symbol解决了属性名称冲突的问题。</p>
<h2 id="8、Proxy"><a href="#8、Proxy" class="headerlink" title="8、Proxy"></a>8、Proxy</h2><h3 id="1-Proxy简介"><a href="#1-Proxy简介" class="headerlink" title="1.Proxy简介"></a>1.Proxy简介</h3><p>Proxy可以理解成在对象前添加了一个“拦截”层，外界在对该对象进行访问时，必须先通过这个拦截层。因此提供了一种机制，可以对外界的访问进行过滤和改写。Proxy这个词的意思是代理的意思，也就是说由Proxy来“代理”某些操作。所以又称之为“代理器”。</p>
<p>Proxy的使用</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> proxy=<span class="keyword">new</span> <span class="title class_">Proxy</span>(target,handler)</span><br></pre></td></tr></table></figure>

<p>target:表示所要拦截的目标对象(原来要访问的对象)</p>
<p>handler:也是一个对象，表示拦截的行为和规则。</p>
<p>要想使用Proxy来完成对象的拦截，除了创建对象以外，还需要指定对应的拦截的方法。</p>
<p>下面使用一下<code>get()</code>这个拦截方法，来体会一下Proxy拦截器的使用。</p>
<p><code>get( )</code>方法用于拦截某个属性的读取操作。</p>
<p>下面先看如下的代码</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> student = &#123;</span><br><span class="line">    <span class="attr">userName</span>: <span class="string">&#x27;张三&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="property">userName</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(student.<span class="property">userAge</span>);</span><br></pre></td></tr></table></figure>

<p>这段代码非常的简单，定义了一个student对象，在该对象中添加了一个userName,下面可以直接通过对象名加上点的方式来获取对应的属性的值。但是，问题是，在student这个对象中，只是定义了userName这个属性，并没有定义userAge,但是当通过student.userAge这个方式来获取的时候，发现得到的结果是undefined.</p>
<p>那么，在这里我们希望如果访问对象中不存在的属性的时候，应该给出相应的错误提示，要想实现这个需求，就要用到Proxy中的<code>get()</code>方法，也就是在访问某个对象的属性之前，先拦截一下，看一下所访问的对象是否有对应的属性，如果有，继续访问，如果没有给用户一个错误的提示。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> student = &#123;</span><br><span class="line">     <span class="attr">userName</span>: <span class="string">&#x27;张三&#x27;</span></span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">let</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(student, &#123;</span><br><span class="line">     <span class="attr">get</span>: <span class="keyword">function</span>(<span class="params">target, property</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (property <span class="keyword">in</span> target) &#123;</span><br><span class="line">             <span class="keyword">return</span> target[property];</span><br><span class="line">         &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">             <span class="comment">// （引用错误） 对象代表当一个不存在的变量被引用时发生的错误。</span></span><br><span class="line">             <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ReferenceError</span>(<span class="string">&#x27;访问的属性&#x27;</span> + property + <span class="string">&quot;不存在&quot;</span>)</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line"> &#125;)</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(proxy.<span class="property">userName</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(proxy.<span class="property">userAge</span>);</span><br></pre></td></tr></table></figure>

<p><code>get()</code> 有两个参数，&#96;第一个参数表示的是目标对象，第二个参数表示的是要访问的属性。</p>
<p>通过上面的代码，可以体会出所谓的 “拦截”的含义了，也就是在访问某个属性的值之前，先判断一下该对象是否有对应的属性，如果有就返回属性的值，没有就给出相应的错误提示。</p>
<p><strong>注意：要使Proxy起作用，必须针对Proxy对象进行操作，不是针对目标对象进行操作(上面的是student对象)。</strong></p>
<h4 id="1-2-set-方法"><a href="#1-2-set-方法" class="headerlink" title="1.2  set( )方法"></a>1.2  set( )方法</h4><p><code>set()</code> 方法用于拦截某个属性的赋值操作。</p>
<p>假如，Student对象有一个age属性，表示学生的年龄，在这里我们要求对年龄进行限制，如果大于60岁，给出错误提示，这样在这里可以使用Proxy对象保证age属性的取值是符合要求的。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> student = &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(student, &#123;</span><br><span class="line">    <span class="attr">set</span>: <span class="keyword">function</span>(<span class="params">obj, prop, value</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;obj=&#x27;</span>, obj);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;prop=&#x27;</span>, prop);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;value=&#x27;</span>, value);</span><br><span class="line">        <span class="keyword">if</span> (prop === <span class="string">&#x27;age&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title class_">Number</span>.<span class="title function_">isInteger</span>(value)) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">TypeError</span>(<span class="string">&#x27;年龄不是整数！&#x27;</span>)</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (value &gt; <span class="number">60</span>) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RangeError</span>(<span class="string">&#x27;年龄太大了&#x27;</span>)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;)</span><br><span class="line">proxy.<span class="property">age</span> = <span class="string">&#x27;80&#x27;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(proxy.<span class="property">age</span>);</span><br></pre></td></tr></table></figure>

<p><code>set()</code>方法</p>
<p>第一个参数：表示拦截的对象。</p>
<p>第二个参数：表示操作的属性名称。</p>
<p>第三个参数：表示属性的值。</p>
<h4 id="1-3-apply-方法"><a href="#1-3-apply-方法" class="headerlink" title="1.3 apply( )方法"></a>1.3 apply( )方法</h4><p><code>apply()</code> 方法拦截函数的调用，函数调用包括直接调用，call函数调用和apply函数调用，三种调用操作方式。</p>
<p>下面先看一下<code>apply()</code>函数的语法</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> handler=&#123;</span><br><span class="line">    <span class="title function_">apply</span>(<span class="params">target,ctx,args</span>)&#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>apply( )</code>函数可以有三个参数,</p>
<p>第一个参数：表示目标对象,也就是要拦截的函数</p>
<p>第二个参数：表示目标对象的上下文对象(this)</p>
<p>第三个参数：表示目标对象的参数数组。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> target = <span class="keyword">function</span>(<span class="params">msg</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;你好&#x27;</span> + msg;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> handler = &#123;</span><br><span class="line">    <span class="attr">apply</span>: <span class="keyword">function</span>(<span class="params">target, ctx, args</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;target=&#x27;</span>, target);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;ctx=&#x27;</span>, ctx === obj);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;args=&#x27;</span>, args);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;hello&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(target, handler);</span><br><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    proxy,</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">proxy</span>(<span class="string">&#x27;张三&#x27;</span>))</span><br></pre></td></tr></table></figure>

<p>在执行target这个方法之前，会被Proxy所拦截。</p>
<h4 id="1-4-has-方法"><a href="#1-4-has-方法" class="headerlink" title="1.4 has( ) 方法"></a>1.4 has( ) 方法</h4><p><code>has()</code> 可以隐藏某些属性，不被in操作符发现。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> user = &#123;</span><br><span class="line">    <span class="attr">_name</span>: <span class="string">&#x27;zhangsan&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> handler = &#123;</span><br><span class="line">    <span class="title function_">has</span>(<span class="params">target, key</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;target=&#x27;</span>, target);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;key=&#x27;</span>, key);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(user, handler);</span><br><span class="line"><span class="string">&#x27;_name&#x27;</span> <span class="keyword">in</span> proxy; <span class="comment">// 自动调用 has 方法</span></span><br></pre></td></tr></table></figure>

<p>通过上面的代码，可以发现：has方法有两个参数，第一个参数：表示目的对象，第二个参数：表示操作的属性。</p>
<p>下面的例子，把<code>user</code> 对象中 <code>_name</code> 属性隐藏起来，也就是无法通过<code>in</code> 运算符发现该属性。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> user = &#123;</span><br><span class="line">    <span class="attr">_name</span>: <span class="string">&#x27;zhangsan&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> handler = &#123;</span><br><span class="line">    <span class="title function_">has</span>(<span class="params">target, key</span>) &#123;</span><br><span class="line">        <span class="comment">// console.log(&#x27;target=&#x27;, target);</span></span><br><span class="line">        <span class="comment">// console.log(&#x27;key=&#x27;, key);</span></span><br><span class="line">        <span class="keyword">if</span> (key[<span class="number">0</span>] === <span class="string">&#x27;_&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> key <span class="keyword">in</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(user, handler);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;_name&#x27;</span> <span class="keyword">in</span> proxy);</span><br></pre></td></tr></table></figure>

<p>上面的代码中，如果对象中的属性名第一个字符是下画线，那么has方法会返回false,从而不会被 <code>in</code> 运算符发现，但是如果将  <code>console.log(&#39;_name&#39; in proxy);</code> 换成   <code>console.log(&#39;age&#39; in proxy);</code>  返回为true.</p>
<h3 id="2、应用场景"><a href="#2、应用场景" class="headerlink" title="2、应用场景"></a>2、应用场景</h3><h4 id="2-1-数据校验"><a href="#2-1-数据校验" class="headerlink" title="2.1 数据校验"></a>2.1 数据校验</h4><p>在前面的课程中，已经讲解过基本的数据校验，下面看一个比较完整的数据校验的案例。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 创建一个对象</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">age</span> = <span class="number">19</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">validator</span>(<span class="variable language_">this</span>, personValidators);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 定义校验规则</span></span><br><span class="line"><span class="keyword">const</span> personValidators = &#123;</span><br><span class="line">        <span class="title function_">name</span>(<span class="params">val</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">typeof</span> val === <span class="string">&#x27;string&#x27;</span>;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">age</span>(<span class="params">val</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">typeof</span> val === <span class="string">&#x27;number&#x27;</span> &amp;&amp; val &gt; <span class="number">18</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 完成校验</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">validator</span>(<span class="params">target, validator</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Proxy</span>(target, &#123;</span><br><span class="line">        <span class="attr">_validator</span>: validator,</span><br><span class="line">        <span class="title function_">set</span>(<span class="params">target, key, value</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (target.<span class="title function_">hasOwnProperty</span>(key)) &#123;</span><br><span class="line">                <span class="keyword">let</span> v = <span class="variable language_">this</span>.<span class="property">_validator</span>[key]; <span class="comment">//根据key获取具体的校验规则</span></span><br><span class="line">                <span class="keyword">if</span> (<span class="title function_">v</span>(value)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">set</span>(target, key, value);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="title class_">Error</span>(<span class="string">`不能给<span class="subst">$&#123;key&#125;</span>属性设置<span class="subst">$&#123;value&#125;</span>`</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="title class_">Error</span>(<span class="string">`<span class="subst">$&#123;key&#125;</span> 不存在`</span>)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 注意这里返回的是Proxy对象</span></span><br><span class="line"><span class="keyword">let</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">person.<span class="property">name</span> = <span class="string">&#x27;zhangsan&#x27;</span>;</span><br><span class="line">person.<span class="property">age</span> = <span class="number">19</span>;</span><br><span class="line"><span class="comment">// person.name = 90;</span></span><br><span class="line"><span class="comment">// person.age = 15;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person);</span><br></pre></td></tr></table></figure>

<p>通过上面的案例，将对象的创建，数据验证的规则，以及具体的验证方式都进行了分离，整体结构更加的清晰，代码更加的容易维护。</p>
<h4 id="2-2-简单模拟双向数据绑定"><a href="#2-2-简单模拟双向数据绑定" class="headerlink" title="2.2 简单模拟双向数据绑定"></a>2.2 简单模拟双向数据绑定</h4><p>大家都知道在<code>V</code>ue&#96;中，是有双向绑定功能的，下面通过Proxy来模拟一下。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"> <span class="keyword">let</span> input = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;txtInput&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> p = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;txtP&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">    <span class="attr">text</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> newObj = <span class="keyword">new</span> <span class="title class_">Proxy</span>(obj, &#123;</span><br><span class="line"></span><br><span class="line">    <span class="attr">set</span>: <span class="keyword">function</span>(<span class="params">target, key, value</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (target.<span class="title function_">hasOwnProperty</span>(key)) &#123;</span><br><span class="line">            input.<span class="property">value</span> = value;</span><br><span class="line">            p.<span class="property">innerHTML</span> = value;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Reflect</span>.<span class="title function_">set</span>(target, key, value);</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">input.<span class="title function_">addEventListener</span>(<span class="string">&#x27;keyup&#x27;</span>, <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span><br><span class="line">    newObj.<span class="property">text</span> = e.<span class="property">target</span>.<span class="property">value</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>在文本框中输入值以后，对应的会在p标签中进行展示，通过在浏览器的控制台中，如果给 newObj中的text属性赋值，对应的文本框和P标签内容也会发生变化。</p>
<h4 id="2-3-实现真正的私有属性"><a href="#2-3-实现真正的私有属性" class="headerlink" title="2.3 实现真正的私有属性"></a>2.3 实现真正的私有属性</h4><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">     <span class="keyword">const</span> userInfo = &#123;</span><br><span class="line">       <span class="attr">_id</span>: <span class="number">123</span>,</span><br><span class="line">       <span class="attr">getAllUsers</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;获取所有用户的信息&quot;</span>);</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">getUserById</span>: <span class="keyword">function</span> (<span class="params">userId</span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;根据用户的编号，查询指定的信息&quot;</span> + userId);</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">saveUser</span>: <span class="keyword">function</span> (<span class="params">user</span>) &#123;</span><br><span class="line">         <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;保存用户信息&quot;</span>);</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;;</span><br><span class="line">     <span class="keyword">const</span> proxy = <span class="keyword">new</span> <span class="title class_">Proxy</span>(userInfo, &#123;</span><br><span class="line">       <span class="attr">get</span>: <span class="keyword">function</span> (<span class="params">target, prop</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (prop[<span class="number">0</span>] === <span class="string">&quot;_&quot;</span>) &#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="literal">undefined</span>;</span><br><span class="line">         &#125;</span><br><span class="line">         <span class="keyword">return</span> target[prop];</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">set</span>: <span class="keyword">function</span> (<span class="params">target, prop, value</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (prop[<span class="number">0</span>] !== <span class="string">&quot;_&quot;</span>) &#123;</span><br><span class="line">           target[prop] = value;</span><br><span class="line">         &#125;</span><br><span class="line">       &#125;,</span><br><span class="line">       <span class="attr">has</span>: <span class="keyword">function</span> (<span class="params">target, prop</span>) &#123;</span><br><span class="line">         <span class="keyword">if</span> (prop[<span class="number">0</span>] === <span class="string">&quot;_&quot;</span>) &#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">         &#125;</span><br><span class="line">         <span class="keyword">return</span> prop <span class="keyword">in</span> target;</span><br><span class="line">       &#125;,</span><br><span class="line">     &#125;);</span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(proxy.<span class="property">_id</span>); <span class="comment">//undefined</span></span><br><span class="line">     proxy.<span class="title function_">getAllUsers</span>(); <span class="comment">// 获取所有用户的信息</span></span><br><span class="line">     proxy.<span class="title function_">getUserById</span>(<span class="number">123</span>); <span class="comment">// 根据用户的编号，查询指定的信息123</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;_id&quot;</span> <span class="keyword">in</span> proxy); <span class="comment">//false</span></span><br><span class="line">     <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;saveUser&quot;</span> <span class="keyword">in</span> proxy); <span class="comment">// true</span></span><br><span class="line">   &lt;/script&gt;</span><br></pre></td></tr></table></figure>

<h2 id="9、Set结构"><a href="#9、Set结构" class="headerlink" title="9、Set结构"></a>9、Set结构</h2><p>Set结构与数组类似，但是成员的值都是唯一的，没有重复值。</p>
<h3 id="1-1-常用的操作方法"><a href="#1-1-常用的操作方法" class="headerlink" title="1.1 常用的操作方法"></a>1.1 常用的操作方法</h3><p>关于常用的操作方法，这里会讲解如下4个。</p>
<p><code>add(value)</code> : 添加某个值，返回Set结构本身。</p>
<p><code>delete(value)</code>: 删除某个值，返回一个布尔值，表示删除是否成功</p>
<p><code>has(value)</code>  : 返回一个布尔值，表示参数是否为Set的成员.</p>
<p><code>clear()</code>: 清除所有成员，没有返回值</p>
<h4 id="1-1-1-add-方法"><a href="#1-1-1-add-方法" class="headerlink" title="1.1.1 add( )方法"></a>1.1.1 add( )方法</h4><p>下面先看一下 <code>add( )</code>方法的使用</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">size</span>);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，用到了size属性，这个属性返回的是Set结构中的成员总数。</p>
<p>Set结构中的成员是不允许出现重复值的，下面测试一下。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">size</span>);</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，又添加了一个数字3，但是在输出的时候，发现3这个数值只出现了一次，并且总数的个数也没有发生变化，所以Set是不允许出现重复的。</p>
<h4 id="1-1-2-has-方法"><a href="#1-1-2-has-方法" class="headerlink" title="1.1.2 has( )方法"></a>1.1.2 has( )方法</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">size</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">3</span>))</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">5</span>))</span><br></pre></td></tr></table></figure>

<h4 id="1-1-3-delete-方法"><a href="#1-1-3-delete-方法" class="headerlink" title="1.1.3 delete( )方法"></a>1.1.3 delete( )方法</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">size</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">delete</span>(<span class="number">3</span>)) <span class="comment">//删除成功返回true.</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">3</span>))</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">5</span>))</span><br></pre></td></tr></table></figure>

<h4 id="1-1-4-clear-方法"><a href="#1-1-4-clear-方法" class="headerlink" title="1.1.4 clear()方法"></a>1.1.4 clear()方法</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">size</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">delete</span>(<span class="number">3</span>))</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">3</span>))</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="title function_">has</span>(<span class="number">5</span>))</span><br><span class="line">s.<span class="title function_">clear</span>();<span class="comment">// 清除所有项</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s);</span><br></pre></td></tr></table></figure>

<p>Set结构是一个类似数组的结构，那么怎样转换成一个真正的数据呢?</p>
<p>可以通过前面学习的 <code>Arrray.from</code>  方法。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">1</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">2</span>);</span><br><span class="line">s.<span class="title function_">add</span>(<span class="number">3</span>);</span><br><span class="line"><span class="keyword">let</span> array = <span class="title class_">Array</span>.<span class="title function_">from</span>(s);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(array);</span><br></pre></td></tr></table></figure>

<p>在使用数组编程的时候，经常会用到一个功能，就是清除数组中的重复的数据，那么在这里可以借助于Set结构来完成。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">      <span class="comment">// 清除数组中的重复数据.</span></span><br><span class="line"><span class="comment">// Set函数可以接受一个数组或者是类似数组的对象，作为参数。</span></span><br><span class="line">      <span class="keyword">let</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">6</span>];</span><br><span class="line">      <span class="keyword">let</span> s = <span class="keyword">new</span> <span class="title class_">Set</span>(array);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">from</span>(s));</span><br></pre></td></tr></table></figure>

</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="http://example.com">Justic</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="http://example.com/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/">http://example.com/2022/07/13/JavaScript/JavaScript 面试精讲/JavaScript面试精讲/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://justicc.top/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="http://example.com" target="_blank">Justic</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/JavaScript/">JavaScript</a></div><div class="post_share"><div class="social-share" data-image="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/wechat.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="/img/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="/img/alipay.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="/img/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E6%A8%A1%E5%9D%97%E5%8C%96/"><img class="prev-cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/m9/wallhaven-m9y289.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">JavaScript 模块化</div></div></a></div><div class="next-post pull-right"><a href="/2022/07/13/Vue/Vue%20Router/vueRouter/"><img class="next-cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/ne/wallhaven-ne8mzl.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Vue 路由</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2022/07/07/JavaScript/JavaScript%E5%BC%95%E6%93%8E/" title="JavaScript 引擎"><img class="cover" src= "" data-lazy-src="https://pic1.zhimg.com/v2-4dce785ff4595de55623611ab0055d33_1440w.jpg?source=172ae18b" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-07</div><div class="title">JavaScript 引擎</div></div></a></div><div><a href="/2022/07/22/JavaScript/JavaScript%E5%87%BD%E6%95%B0this%E6%8C%87%E5%90%91/JavaScript%E5%87%BD%E6%95%B0this%E6%8C%87%E5%90%91/" title="JavaScript函数this指向"><img class="cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/k7/wallhaven-k7jmg6.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-22</div><div class="title">JavaScript函数this指向</div></div></a></div><div><a href="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/" title="JavaScript 性能优化"><img class="cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/3z/wallhaven-3zgz2y.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-13</div><div class="title">JavaScript 性能优化</div></div></a></div><div><a href="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/JavaScript%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/" title="JavaScript 异步编程"><img class="cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/j3/wallhaven-j3qq15.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-13</div><div class="title">JavaScript 异步编程</div></div></a></div><div><a href="/2022/07/13/JavaScript/JavaScript%20%E9%9D%A2%E8%AF%95%E7%B2%BE%E8%AE%B2/%E6%A8%A1%E5%9D%97%E5%8C%96/" title="JavaScript 模块化"><img class="cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/m9/wallhaven-m9y289.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-13</div><div class="title">JavaScript 模块化</div></div></a></div><div><a href="/2022/08/08/JavaScript/JavaScript%E5%87%BD%E6%95%B0%E5%A2%9E%E5%BC%BA%E7%9F%A5%E8%AF%86/index/" title="JavaScript函数增强知识"><img class="cover" src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/28/wallhaven-2881yx.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-08</div><div class="title">JavaScript函数增强知识</div></div></a></div></div></div><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src= "" data-lazy-src="https://portrait.gitee.com/uploads/avatars/user/2982/8948190_JIAXInT_1624177607.png!avatar200" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">Justic</div><div class="author-info__description">最是人间留不住 朱颜辞镜花辞树</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">25</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">2</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">3</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/xxxxxx"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my Blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%80%E3%80%81JavaScript%E5%9F%BA%E7%A1%80"><span class="toc-text">一、JavaScript基础</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E4%BB%8B%E7%BB%8D"><span class="toc-text">1、基本数据类型介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-Undefined%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.1 Undefined类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-Null%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.2 Null类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-Undefined%E4%B8%8Enull%E6%AF%94%E8%BE%83"><span class="toc-text">1.3 Undefined与null比较</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-Boolean%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.4  Boolean类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-Number%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.5 Number类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-1-Number%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2"><span class="toc-text">1.5.1 Number类型转换</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-5-2-isNaN-%E5%87%BD%E6%95%B0%E4%B8%8ENumber-isNaN-%E5%87%BD%E6%95%B0%E5%AF%B9%E6%AF%94"><span class="toc-text">1.5.2  isNaN( )函数与Number.isNaN( )函数对比</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-6-String%E7%B1%BB%E5%9E%8B"><span class="toc-text">1.6 String类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-6-1-String%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89"><span class="toc-text">1.6.1 String类型定义</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-6-2-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95"><span class="toc-text">1.6.2  字符串常见算法</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2、运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E7%AD%89%E4%BA%8E%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2.1 等于运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-1-%E4%B8%89%E7%AD%89%E4%BA%8E%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2.1.1 三等于运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-2-%E5%8F%8C%E7%AD%89%E4%BA%8E%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2.1.2 双等于运算符</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-typeof%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2.2 typeof运算符</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E5%B8%B8%E7%94%A8%E7%9A%84%E5%88%A4%E7%A9%BA%E6%96%B9%E6%B3%95"><span class="toc-text">3、常用的判空方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6"><span class="toc-text">4、流程控制</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E5%BC%95%E7%94%A8%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-text">二、引用数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81Object%E7%B1%BB%E5%9E%8B"><span class="toc-text">1、Object类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-new-%E6%93%8D%E4%BD%9C%E7%AC%A6%E7%9A%84%E4%BD%9C%E7%94%A8"><span class="toc-text">1.1  new 操作符的作用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E7%90%86%E8%A7%A3"><span class="toc-text">1.2 原型对象理解</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%87%BD%E6%95%B0%E5%AF%B9%E8%B1%A1%E7%9A%84-prototype-%E5%B1%9E%E6%80%A7"><span class="toc-text">函数对象的 prototype 属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#constructor-%E5%B1%9E%E6%80%A7"><span class="toc-text">constructor 属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AF%B9%E8%B1%A1%E7%9A%84-proto-%E5%B1%9E%E6%80%A7"><span class="toc-text">对象的 __proto__ 属性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-%E5%8E%9F%E5%9E%8B%E5%B1%9E%E6%80%A7"><span class="toc-text">1.3 原型属性</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%B1%9E%E6%80%A7%E8%AE%BF%E9%97%AE"><span class="toc-text">属性访问</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%B1%9E%E6%80%A7%E5%88%A4%E6%96%AD"><span class="toc-text">属性判断</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E8%8E%B7%E5%8F%96"><span class="toc-text">所有属性获取</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-Object-create-%E6%96%B9%E6%B3%95"><span class="toc-text">1.4 Object.create( )方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">基本使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-text">实现原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">应用场景</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-Object-create-%E4%B8%8Enew-Object-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">1.5 Object.create( )与new Object()的区别</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-6-%E6%A8%A1%E6%8B%9Fnew%E6%93%8D%E4%BD%9C%E7%AC%A6%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-text">1.6 模拟new操作符的实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-7-%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%90%86%E8%A7%A3"><span class="toc-text">1.7 原型链理解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-8-%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%89%B9%E7%82%B9"><span class="toc-text">1.8 原型链特点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-9-%E5%B1%9E%E6%80%A7%E7%9A%84%E5%8C%BA%E5%88%86"><span class="toc-text">1.9 属性的区分</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81Array%E7%B1%BB%E5%9E%8B"><span class="toc-text">2、Array类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E6%80%8E%E6%A0%B7-%E5%88%A4%E6%96%AD%E4%B8%80%E4%B8%AA%E5%8F%98%E9%87%8F%E6%98%AF%E6%95%B0%E7%BB%84%E8%BF%98%E6%98%AF%E5%AF%B9%E8%B1%A1"><span class="toc-text">2.1 怎样 判断一个变量是数组还是对象</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-1-instanceof%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">2.1.1 instanceof运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-2-%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%9D%A5%E5%88%A4%E6%96%AD"><span class="toc-text">2.1.2  通过构造函数来判断</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-3-%E9%80%9A%E8%BF%87toString-%E5%87%BD%E6%95%B0%E6%9D%A5%E5%88%A4%E6%96%AD"><span class="toc-text">2.1.3 通过toString( )函数来判断</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-4-%E9%80%9A%E8%BF%87Array-isArray-%E5%87%BD%E6%95%B0%E6%9D%A5%E5%88%A4%E6%96%AD"><span class="toc-text">2.1.4  通过Array.isArray( )函数来判断</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-%E6%80%8E%E6%A0%B7%E8%BF%87%E6%BB%A4%E6%95%B0%E7%BB%84%E4%B8%AD%E6%BB%A1%E8%B6%B3%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%95%B0%E6%8D%AE"><span class="toc-text">2.2 怎样过滤数组中满足条件的数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-%E6%80%8E%E6%A0%B7%E5%AF%B9%E6%95%B0%E7%BB%84%E5%85%83%E7%B4%A0%E5%81%9A%E7%B4%AF%E5%8A%A0%E5%A4%84%E7%90%86"><span class="toc-text">2.3 怎样对数组元素做累加处理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-%E6%80%8E%E6%A0%B7%E6%B1%82%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%9C%80%E5%A4%A7%E5%80%BC%E4%B8%8E%E6%9C%80%E5%B0%8F%E5%80%BC"><span class="toc-text">2.4 怎样求数组中的最大值与最小值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86%E7%9A%84%E6%96%B9%E5%BC%8F%E6%9C%89%E5%93%AA%E4%BA%9B"><span class="toc-text">2.5 数组遍历的方式有哪些</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%9A%E8%BF%87for%E5%BE%AA%E7%8E%AF"><span class="toc-text">通过for循环</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8forEach-%E5%87%BD%E6%95%B0"><span class="toc-text">使用forEach( )函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8map-%E5%87%BD%E6%95%B0"><span class="toc-text">使用map( )函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8some-%E5%87%BD%E6%95%B0%E4%B8%8Eevery-%E5%87%BD%E6%95%B0"><span class="toc-text">使用some( )函数与every( )函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8find-%E5%87%BD%E6%95%B0"><span class="toc-text">使用find( )函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0find%E6%96%B9%E6%B3%95"><span class="toc-text">2.6 手动实现find方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0filter%E6%96%B9%E6%B3%95"><span class="toc-text">2.7  手动实现filter方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-8-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0some%E5%87%BD%E6%95%B0"><span class="toc-text">2.8 手动实现some函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-9-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0every%E5%87%BD%E6%95%B0"><span class="toc-text">2.9  手动实现every函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-10-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0map%E6%96%B9%E6%B3%95"><span class="toc-text">2.10 手动实现map方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-11-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0reduce%E6%96%B9%E6%B3%95"><span class="toc-text">2.11 手动实现reduce方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-12-%E6%80%8E%E6%A0%B7%E5%AE%9E%E7%8E%B0%E6%95%B0%E7%BB%84%E7%9A%84%E5%8E%BB%E9%87%8D"><span class="toc-text">2.12 怎样实现数组的去重</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A9%E7%94%A8%E6%95%B0%E7%BB%84%E9%81%8D%E5%8E%86%E5%8E%BB%E9%87%8D"><span class="toc-text">利用数组遍历去重</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A9%E7%94%A8%E9%94%AE%E5%80%BC%E5%AF%B9%E5%8E%BB%E9%87%8D"><span class="toc-text">利用键值对去重</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8Set%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8E%BB%E9%87%8D"><span class="toc-text">使用Set数据结构去重</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-13-%E6%80%8E%E6%A0%B7%E8%8E%B7%E5%8F%96%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9C%80%E5%A4%9A%E7%9A%84%E5%85%83%E7%B4%A0"><span class="toc-text">2.13 怎样获取数组中最多的元素</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A9%E7%94%A8%E9%94%AE%E5%80%BC%E5%AF%B9%E5%AE%9E%E7%8E%B0"><span class="toc-text">利用键值对实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%AE%97%E6%B3%95%E4%BC%98%E5%8C%96"><span class="toc-text">算法优化</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E5%87%BD%E6%95%B0"><span class="toc-text">三、函数</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E6%9C%89%E5%93%AA%E5%87%A0%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F"><span class="toc-text">1、函数定义有哪几种实现方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81Function-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">2、Function( )构造函数定义函数的问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">3、函数表达式的应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E5%87%BD%E6%95%B0%E5%A3%B0%E6%98%8E%E4%B8%8E%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB"><span class="toc-text">4、函数声明与函数表达式有什么区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E5%87%BD%E6%95%B0%E5%B8%B8%E8%A7%81%E7%9A%84%E8%B0%83%E7%94%A8%E6%A8%A1%E5%BC%8F%E6%9C%89%E5%93%AA%E4%BA%9B"><span class="toc-text">5、函数常见的调用模式有哪些</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E5%AE%9E%E5%8F%82%E4%B8%8E%E5%BD%A2%E5%8F%82%E6%9C%89%E5%93%AA%E4%BA%9B%E5%8C%BA%E5%88%AB"><span class="toc-text">6、实参与形参有哪些区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E4%BB%8B%E7%BB%8D%E4%B8%80%E4%B8%8Barguments%E5%AF%B9%E8%B1%A1"><span class="toc-text">7、介绍一下arguments对象</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81arguments%E5%AF%B9%E8%B1%A1%E6%9C%89%E5%93%AA%E4%BA%9B%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">8、arguments对象有哪些应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81%E8%AF%B4%E4%B8%80%E4%B8%8B%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%E4%B8%8E%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">9、说一下普通函数与构造函数的区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87%EF%BC%8C%E4%BB%80%E4%B9%88%E6%98%AF%E5%87%BD%E6%95%B0%E6%8F%90%E5%8D%87"><span class="toc-text">10、什么是变量提升，什么是函数提升</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="toc-text">作用域</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9D%A2%E8%AF%95%E4%B8%AD%E5%85%B3%E4%BA%8E%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E4%BD%9C%E7%94%A8%E5%9F%9F%E9%93%BE%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">面试中关于作用域与作用域链的问题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87"><span class="toc-text">变量提升</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%87%BD%E6%95%B0%E6%8F%90%E5%8D%87"><span class="toc-text">函数提升</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11%E3%80%81%E9%97%AD%E5%8C%85"><span class="toc-text">11、闭包</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87%E7%8E%AF%E5%A2%83"><span class="toc-text">执行上下文环境</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E9%97%AD%E5%8C%85"><span class="toc-text">什么是闭包</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%97%AD%E5%8C%85%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">闭包的应用场景</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%97%AD%E5%8C%85%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98"><span class="toc-text">闭包常见面试题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%97%AD%E5%8C%85%E4%BC%98%E7%BC%BA%E7%82%B9"><span class="toc-text">闭包优缺点</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12%E3%80%81this%E6%8C%87%E5%90%91"><span class="toc-text">12、this指向</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98"><span class="toc-text">常见面试题</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#13%E3%80%81call-%E5%87%BD%E6%95%B0%EF%BC%8Capply-%E5%87%BD%E6%95%B0%EF%BC%8Cbind-%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%BF%E7%94%A8%E4%B8%8E%E5%8C%BA%E5%88%AB"><span class="toc-text">13、call()函数，apply( )函数，bind( )函数的使用与区别</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#call-%E5%87%BD%E6%95%B0%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">call( )函数的基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#apply-%E5%87%BD%E6%95%B0%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">apply( )函数的基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#bind%E5%87%BD%E6%95%B0%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">bind函数的基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%89%E4%B8%AA%E5%87%BD%E6%95%B0%E7%9A%84%E6%AF%94%E8%BE%83"><span class="toc-text">三个函数的比较</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF-1"><span class="toc-text">应用场景</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%8B%E5%86%99call%E3%80%81apply%E5%8F%8Abind%E5%87%BD%E6%95%B0"><span class="toc-text">手写call、apply及bind函数</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#14%E3%80%81%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E6%9C%89%E4%BB%80%E4%B9%88%E7%BC%BA%E7%82%B9"><span class="toc-text">14、回调函数有什么缺点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#15%E3%80%81-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%87%BD%E6%95%B0%E8%A2%AB%E7%A7%B0%E4%B8%BA%E4%B8%80%E7%AD%89%E5%85%AC%E6%B0%91%EF%BC%9F"><span class="toc-text">15、 为什么函数被称为一等公民？</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-text"></span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9B%9B%E3%80%81%E5%AF%B9%E8%B1%A1"><span class="toc-text">四、对象</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="toc-text">1、对象的属性</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E5%B1%9E%E6%80%A7%E8%AE%BF%E9%97%AE%E6%96%B9%E5%BC%8F%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">2、属性访问方式的区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E6%9C%89%E5%93%AA%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F"><span class="toc-text">3、创建对象有哪几种方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E5%AF%B9%E8%B1%A1%E6%8B%B7%E8%B4%9D"><span class="toc-text">4、对象拷贝</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%85%E6%8B%B7%E8%B4%9D"><span class="toc-text">浅拷贝</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B7%B1%E6%8B%B7%E8%B4%9D"><span class="toc-text">深拷贝</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E9%87%8D%E5%86%99%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">5、重写原型对象的问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E7%BB%A7%E6%89%BF%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%E6%9C%89%E5%93%AA%E4%BA%9B"><span class="toc-text">6、继承的实现方式有哪些</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%BB%A7%E6%89%BF"><span class="toc-text">原型链继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%BB%A7%E6%89%BF"><span class="toc-text">构造函数继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8B%B7%E8%B4%9D%E7%BB%A7%E6%89%BF"><span class="toc-text">拷贝继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E7%BB%A7%E6%89%BF"><span class="toc-text">组合继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%84%E7%94%9F%E5%BC%8F%E7%BB%84%E5%90%88%E7%BB%A7%E6%89%BF"><span class="toc-text">寄生式组合继承</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E6%A8%A1%E6%8B%9FjQuery%E5%AE%9E%E7%8E%B0"><span class="toc-text">7、模拟jQuery实现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%8B%E9%9D%A2%E6%88%91%E4%BB%AC%E5%AE%9E%E7%8E%B0jQuery%E7%9A%84%E6%89%A9%E5%B1%95%E5%8A%9F%E8%83%BD"><span class="toc-text">**下面我们实现jQuery的扩展功能</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%94%E3%80%81DOM%E4%B8%8E%E4%BA%8B%E4%BB%B6"><span class="toc-text">五、DOM与事件</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E9%80%89%E6%8B%A9%E5%99%A8"><span class="toc-text">1、选择器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81HTMLCollection%E5%AF%B9%E8%B1%A1%E4%B8%8ENodeList%E5%AF%B9%E8%B1%A1%E5%8C%BA%E5%88%AB"><span class="toc-text">2、HTMLCollection对象与NodeList对象区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E5%B8%B8%E8%A7%81%E7%9A%84DOM%E6%93%8D%E4%BD%9C%E6%9C%89%E5%93%AA%E4%BA%9B%EF%BC%9F"><span class="toc-text">3、常见的DOM操作有哪些？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81DOM%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98"><span class="toc-text">4、DOM性能问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E4%BC%A0%E6%92%AD"><span class="toc-text">5、什么是事件传播</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E7%9A%84%E6%8D%95%E8%8E%B7"><span class="toc-text">6、什么是事件的捕获</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1"><span class="toc-text">7、什么是事件冒泡</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81%E9%98%BB%E6%AD%A2%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1"><span class="toc-text">8、阻止事件冒泡</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E4%B8%8E%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7%E9%97%AE%E9%A2%98"><span class="toc-text">9、事件冒泡与事件捕获问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10%E3%80%81Event%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8"><span class="toc-text">10、Event对象使用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11%E3%80%81%E4%BB%8B%E7%BB%8D%E4%B8%80%E4%B8%8B%E4%B8%89%E7%A7%8D%E4%BA%8B%E4%BB%B6%E6%A8%A1%E5%9E%8B"><span class="toc-text">11、介绍一下三种事件模型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#12%E3%80%81%E4%BB%8B%E7%BB%8D%E4%B8%80%E4%B8%8B%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%89%98"><span class="toc-text">12、介绍一下事件委托</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#13%E3%80%81%E4%BB%8B%E7%BB%8D%E4%B8%80%E4%B8%8B%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E9%87%8D%E6%8E%92%E4%B8%8E%E9%87%8D%E7%BB%98"><span class="toc-text">13、介绍一下浏览器的重排与重绘</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AD%E3%80%81AJAX"><span class="toc-text">六、AJAX</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AFAJAX"><span class="toc-text">1、什么是AJAX</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81AJAX%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88"><span class="toc-text">2、AJAX原理是什么</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81AJAX%E5%9F%BA%E6%9C%AC%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-text">3、AJAX基本的使用</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AFreadyState%EF%BC%9F"><span class="toc-text">什么是readyState？</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AFstatus%EF%BC%9F"><span class="toc-text">什么是status？</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81AJAX%E4%BC%98%E7%BC%BA%E7%82%B9%E5%88%86%E6%9E%90"><span class="toc-text">4、AJAX优缺点分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81Get%E5%92%8CPost%E8%AF%B7%E6%B1%82%E6%95%B0%E6%8D%AE%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">5、Get和Post请求数据的区别</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81Get%E5%92%8CPost%E8%AF%B7%E6%B1%82%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">6、Get和Post请求的应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E6%B5%8F%E8%A7%88%E5%99%A8%E5%90%8C%E6%BA%90%E7%AD%96%E7%95%A5"><span class="toc-text">7、浏览器同源策略</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BC%9A%E6%9C%89%E8%B7%A8%E5%9F%9F%E9%99%90%E5%88%B6%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%9F"><span class="toc-text">8、为什么浏览器会有跨域限制的问题？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98%E6%BC%94%E7%A4%BA"><span class="toc-text">9、跨域问题演示</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10%E3%80%81CORS"><span class="toc-text">10、CORS</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#11%E3%80%81JSONP"><span class="toc-text">11、JSONP</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%83%E3%80%81ES6"><span class="toc-text">七、ES6</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81let-%E5%85%B3%E9%94%AE%E5%AD%97"><span class="toc-text">1、let 关键字</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95"><span class="toc-text">1.1 基本用法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-let%E4%B8%8Evar%E5%8C%BA%E5%88%AB"><span class="toc-text">1.2 let与var区别</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="toc-text">1.3 块级作用域</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-1-%E4%BB%80%E4%B9%88%E6%98%AF%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F%EF%BC%9F"><span class="toc-text">1.3.1 什么是块级作用域？</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-2-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F%EF%BC%9F"><span class="toc-text">1.3.2  为什么需要块级作用域？</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-3-ES6%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="toc-text">1.3.3 ES6块级作用域</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-let%E5%91%BD%E4%BB%A4%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">1.4 let命令注意事项</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-1-%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87"><span class="toc-text">1.4.1 不存在变量提升</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-2-%E6%9A%82%E6%97%B6%E6%80%A7%E6%AD%BB%E5%8C%BA"><span class="toc-text">1.4.2 暂时性死区</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-3-%E4%B8%8D%E5%85%81%E8%AE%B8%E9%87%8D%E5%A4%8D%E5%A3%B0%E6%98%8E"><span class="toc-text">1.4.3  不允许重复声明</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81const%E5%91%BD%E4%BB%A4"><span class="toc-text">2、const命令</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95"><span class="toc-text">2.1 基本用法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-const%E5%91%BD%E4%BB%A4%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">2.2 const命令注意事项</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-1-%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%B8%B8%E9%87%8F%E6%8F%90%E5%8D%87"><span class="toc-text">2.2.1 不存在常量提升</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-2-%E5%8F%AA%E5%9C%A8%E5%A3%B0%E6%98%8E%E7%9A%84%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%86%85%E6%9C%89%E6%95%88"><span class="toc-text">2.2.2 只在声明的块级作用域内有效</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-3-%E6%9A%82%E6%97%B6%E6%80%A7%E6%AD%BB%E5%8C%BA"><span class="toc-text">2.2.3 暂时性死区</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-4-%E4%B8%8D%E5%85%81%E8%AE%B8%E9%87%8D%E5%A4%8D%E5%A3%B0%E6%98%8E"><span class="toc-text">2.2.4 不允许重复声明</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-5-%E5%B8%B8%E9%87%8F%E5%A3%B0%E6%98%8E%E5%BF%85%E9%A1%BB%E8%B5%8B%E5%80%BC"><span class="toc-text">2.2.5 常量声明必须赋值</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC"><span class="toc-text">3、解构赋值</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1%E3%80%81%E6%95%B0%E7%BB%84%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95"><span class="toc-text">3.1、数组解构赋值基本用法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2%E3%80%81%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">3.2、注意事项</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#3-2-1-%E5%A6%82%E6%9E%9C%E8%A7%A3%E6%9E%90%E4%B8%8D%E6%88%90%E5%8A%9F%EF%BC%8C%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E4%BC%9A%E4%B8%BAundefined"><span class="toc-text">3.2.1  如果解析不成功，对应的值会为undefined.</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-2-2-%E4%B8%8D%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%84%E7%9A%84%E6%83%85%E5%86%B5"><span class="toc-text">3.2.2  不完全解构的情况</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4%E3%80%81%E5%AF%B9%E8%B1%A1%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">3.4、对象解构赋值基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5%E3%80%81%E5%AF%B9%E8%B1%A1%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">3.5、对象解构赋值注意事项</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-1-%E9%BB%98%E8%AE%A4%E8%A7%A3%E6%9E%84"><span class="toc-text">3.5.1 默认解构</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-2-%E5%B5%8C%E5%A5%97%E7%BB%93%E6%9E%84%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%A7%A3%E6%9E%84"><span class="toc-text">3.5.2  嵌套结构对象的解构</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6%E3%80%81%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC"><span class="toc-text">3.6、字符串的解构赋值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7%E3%80%81%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%9A%84%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC"><span class="toc-text">3.7、函数参数的解构赋值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-8%E3%80%81%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E7%9A%84%E5%A5%BD%E5%A4%84"><span class="toc-text">3.8、解构赋值的好处</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-8-1-%E4%BA%A4%E6%8D%A2%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC"><span class="toc-text">3.8.1 交换变量的值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-8-2-%E5%87%BD%E6%95%B0%E5%8F%AF%E4%BB%A5%E8%BF%94%E5%9B%9E%E5%A4%9A%E4%B8%AA%E5%80%BC"><span class="toc-text">3.8.2 函数可以返回多个值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-8-3-%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1"><span class="toc-text">3.8.3 函数返回一个对象</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-8-4-%E6%8F%90%E5%8F%96JSON%E5%AF%B9%E8%B1%A1%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE"><span class="toc-text">3.8.4 提取JSON对象中的数据</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6%E4%B8%8Erest%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">4、扩展运算符与rest运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">4.1 扩展运算符</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">4.2 扩展运算符应用场景</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-1-%E4%BB%A3%E6%9B%BF%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84apply%E6%96%B9%E6%B3%95"><span class="toc-text">4.2.1 代替数组中的apply方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-2-%E7%94%A8%E4%BA%8E%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8"><span class="toc-text">4.2.2 用于函数调用</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-rest%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">4.3 rest运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-1-rest%E5%8F%82%E6%95%B0%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">4.3.1 rest参数基本使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-2-rest%E5%8F%82%E6%95%B0%E7%9A%84%E5%A5%BD%E5%A4%84"><span class="toc-text">4.3.2 rest参数的好处</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-3-rest%E5%8F%82%E6%95%B0%E6%B3%A8%E6%84%8F%E9%97%AE%E9%A2%98"><span class="toc-text">4.3.3 rest参数注意问题</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0"><span class="toc-text">5、什么是箭头函数</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">5.1 箭头函数基本使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">5.2  箭头函数注意事项</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-1-%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1"><span class="toc-text">5.2.1 直接返回对象</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-2-%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E4%B8%ADthis%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">5.2.2 箭头函数中this的问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-3-3-%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E4%B8%8D%E9%80%82%E5%90%88%E7%9A%84%E5%9C%BA%E6%99%AF"><span class="toc-text">5.3.3 箭头函数不适合的场景</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%89%A9%E5%B1%95"><span class="toc-text">6、对象的扩展</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%E3%80%81%E5%B1%9E%E6%80%A7%E4%B8%8E%E6%96%B9%E6%B3%95%E7%9A%84%E7%AE%80%E6%B4%81%E8%A1%A8%E7%A4%BA%E6%96%B9%E5%BC%8F"><span class="toc-text">1、属性与方法的简洁表示方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81Object-assign-%E6%96%B9%E6%B3%95"><span class="toc-text">2、Object.assign( )方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8"><span class="toc-text">2.1 基本使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-%E6%B7%B1%E6%B5%85%E6%8B%B7%E8%B4%9D%E9%97%AE%E9%A2%98"><span class="toc-text">2.2  深浅拷贝问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-text">2.3 注意事项</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81Symbol"><span class="toc-text">7、Symbol</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1%E3%80%81Symbol%E7%AE%80%E4%BB%8B"><span class="toc-text">7.1、Symbol简介</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2%E3%80%81Symbol%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">7.2、Symbol应用场景</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-1-%E4%BD%9C%E4%B8%BA%E5%B1%9E%E6%80%A7%E5%90%8D%E7%9A%84Symbol"><span class="toc-text">7.2.1 作为属性名的Symbol</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-2-%E9%98%B2%E6%AD%A2%E5%B1%9E%E6%80%A7%E5%90%8D%E7%A7%B0%E5%86%B2%E7%AA%81"><span class="toc-text">7.2.2  防止属性名称冲突</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81Proxy"><span class="toc-text">8、Proxy</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-Proxy%E7%AE%80%E4%BB%8B"><span class="toc-text">1.Proxy简介</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-set-%E6%96%B9%E6%B3%95"><span class="toc-text">1.2  set( )方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-apply-%E6%96%B9%E6%B3%95"><span class="toc-text">1.3 apply( )方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-4-has-%E6%96%B9%E6%B3%95"><span class="toc-text">1.4 has( ) 方法</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%E3%80%81%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">2、应用场景</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-%E6%95%B0%E6%8D%AE%E6%A0%A1%E9%AA%8C"><span class="toc-text">2.1 数据校验</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-%E7%AE%80%E5%8D%95%E6%A8%A1%E6%8B%9F%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A"><span class="toc-text">2.2 简单模拟双向数据绑定</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-%E5%AE%9E%E7%8E%B0%E7%9C%9F%E6%AD%A3%E7%9A%84%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7"><span class="toc-text">2.3 实现真正的私有属性</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81Set%E7%BB%93%E6%9E%84"><span class="toc-text">9、Set结构</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-%E5%B8%B8%E7%94%A8%E7%9A%84%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95"><span class="toc-text">1.1 常用的操作方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-1-add-%E6%96%B9%E6%B3%95"><span class="toc-text">1.1.1 add( )方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-2-has-%E6%96%B9%E6%B3%95"><span class="toc-text">1.1.2 has( )方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-3-delete-%E6%96%B9%E6%B3%95"><span class="toc-text">1.1.3 delete( )方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-4-clear-%E6%96%B9%E6%B3%95"><span class="toc-text">1.1.4 clear()方法</span></a></li></ol></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2022/11/09/JavaScript/ES6%E6%96%B0%E7%89%B9%E6%80%A7/index/" title="ES6新特性"><img src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/m9/wallhaven-m9y289.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="ES6新特性"/></a><div class="content"><a class="title" href="/2022/11/09/JavaScript/ES6%E6%96%B0%E7%89%B9%E6%80%A7/index/" title="ES6新特性">ES6新特性</a><time datetime="2022-11-09T12:55:33.000Z" title="发表于 2022-11-09 20:55:33">2022-11-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/11/09/123/" title="123"><img src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="123"/></a><div class="content"><a class="title" href="/2022/11/09/123/" title="123">123</a><time datetime="2022-11-09T12:40:11.000Z" title="发表于 2022-11-09 20:40:11">2022-11-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/11/09/ES6%E6%96%B0%E7%89%B9%E6%80%A7-1/" title="ES6新特性"><img src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="ES6新特性"/></a><div class="content"><a class="title" href="/2022/11/09/ES6%E6%96%B0%E7%89%B9%E6%80%A7-1/" title="ES6新特性">ES6新特性</a><time datetime="2022-11-09T12:38:06.000Z" title="发表于 2022-11-09 20:38:06">2022-11-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/11/09/ES6%E6%96%B0%E7%89%B9%E6%80%A7/" title="ES6新特性"><img src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/j3/wallhaven-j3qq15.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="ES6新特性"/></a><div class="content"><a class="title" href="/2022/11/09/ES6%E6%96%B0%E7%89%B9%E6%80%A7/" title="ES6新特性">ES6新特性</a><time datetime="2022-11-09T12:35:33.000Z" title="发表于 2022-11-09 20:35:33">2022-11-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2022/10/20/Vue/Vue%20%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A7%A3%E6%9E%90/Vue%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A7%A3%E6%9E%90/" title="Vue 响应式解析"><img src= "" data-lazy-src="https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Vue 响应式解析"/></a><div class="content"><a class="title" href="/2022/10/20/Vue/Vue%20%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A7%A3%E6%9E%90/Vue%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A7%A3%E6%9E%90/" title="Vue 响应式解析">Vue 响应式解析</a><time datetime="2022-10-20T12:05:37.000Z" title="发表于 2022-10-20 20:05:37">2022-10-20</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/z8/wallhaven-z82evv.jpg')"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2022 By Justic</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a><img src= "" data-lazy-src="https://static.dy208.cn/o_1dfilp8ruo521thr1hvf18ji17soa.png">
<a href="http://www.beian.miit.gov.cn/"  style="color:#f72b07" target="_blank">晋ICP备2021014440号-2</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="chat_btn" type="button" title="聊天"><i class="fas fa-sms"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"><script>function loadValine () {
  function initValine () {
    const valine = new Valine(Object.assign({
      el: '#vcomment',
      appId: 'KgIigedIwh0GobYsWWfPMEdO-gzGzoHsz',
      appKey: 'WpJEQP22asTau19i2tq1yQhU',
      avatar: 'justic',
      serverURLs: '',
      emojiMaps: "",
      path: window.location.pathname,
      visitor: false
    }, null))
  }

  if (typeof Valine === 'function') initValine() 
  else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
}

if ('Valine' === 'Valine' || !false) {
  if (false) btf.loadComment(document.getElementById('vcomment'),loadValine)
  else setTimeout(loadValine, 0)
} else {
  function loadOtherComment () {
    loadValine()
  }
}</script></div><div class="aplayer no-destroy" data-id="5076309057" data-server="netease" data-type="playlist" data-fixed="true" data-autoplay="true" data-lrcType="-1"> </div><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-nest.min.js"></script><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = false;
POWERMODE.mobile = true;
document.body.addEventListener('input', POWERMODE);
</script><script id="click-show-text" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/click-show-text.min.js" data-mobile="true" data-text="富强,民主,文明,和谐,平等,公正,法治,爱国,敬业,诚信,友善" data-fontsize="15px" data-random="true" async="async"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/metingjs/dist/Meting.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><!-- hexo injector body_end start --><script data-pjax>
  function butterfly_clock_anzhiyu_injector_config(){
    var parent_div_git = document.getElementsByClassName('sticky_layout')[0];
    var item_html = '<div class="card-widget card-clock"><div class="card-glass"><div class="card-background"><div class="card-content"><div id="hexo_electric_clock"><img class="entered loading" id="card-clock-loading" src= "" data-lazy-src="https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/loading.gif" style="height: 120px; width: 100%;" data-ll-status="loading"/></div></div></div></div></div>';
    console.log('已挂载butterfly_clock_anzhiyu')
    parent_div_git.insertAdjacentHTML("afterbegin",item_html)
    }
  var elist = 'null'.split(',');
  var cpage = location.pathname;
  var epage = 'all';
  var qweather_key = 'f854dfdd82d747fca7fd04f092861e87';
  var gaud_map_key = '427416c518f4476a01117be40057a892';
  var baidu_ak_key = 'undefined';
  var flag = 0;
  var clock_rectangle = '112.982279,28.19409';
  var clock_default_rectangle_enable = 'false';

  for (var i=0;i<elist.length;i++){
    if (cpage.includes(elist[i])){
      flag++;
    }
  }

  if ((epage ==='all')&&(flag == 0)){
    butterfly_clock_anzhiyu_injector_config();
  }
  else if (epage === cpage){
    butterfly_clock_anzhiyu_injector_config();
  }
  </script><script src="https://widget.qweather.net/simple/static/js/he-simple-common.js?v=2.0"></script><script data-pjax src="https://cdn.cbd.int/hexo-butterfly-clock-anzhiyu/lib/clock.min.js"></script><!-- hexo injector body_end end --></body></html>